summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-10-08 09:14:03 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-10-08 09:14:03 +0900
commitd140263a497b4a86818ab5e2017a66df43eb83fb (patch)
tree4acfe8c906ce669c5fc92689df2c3c83a32d881c
parente1763ae434c946bd1c1e9a7cc66a905ebe027bbd (diff)
downloadcmake-d140263a497b4a86818ab5e2017a66df43eb83fb.tar.gz
cmake-d140263a497b4a86818ab5e2017a66df43eb83fb.tar.bz2
cmake-d140263a497b4a86818ab5e2017a66df43eb83fb.zip
Imported Upstream version 3.15.0upstream/3.15.0
-rw-r--r--.clang-tidy2
-rw-r--r--Auxiliary/bash-completion/cmake5
-rw-r--r--Auxiliary/cmake.m42
-rw-r--r--Auxiliary/vim/cmake.vim.in4
-rwxr-xr-xAuxiliary/vim/extract-upper-case.pl18
-rw-r--r--Auxiliary/vim/syntax/cmake.vim881
-rw-r--r--CMakeCPack.cmake3
-rw-r--r--CMakeCPackOptions.cmake.in10
-rw-r--r--CMakeLists.txt35
-rw-r--r--CompileFlags.cmake20
-rw-r--r--Help/command/add_custom_command.rst8
-rw-r--r--Help/command/add_custom_target.rst8
-rw-r--r--Help/command/add_definitions.rst2
-rw-r--r--Help/command/add_library.rst23
-rw-r--r--Help/command/add_link_options.rst17
-rw-r--r--Help/command/add_test.rst3
-rw-r--r--Help/command/aux_source_directory.rst4
-rw-r--r--Help/command/build_command.rst2
-rw-r--r--Help/command/cmake_parse_arguments.rst26
-rw-r--r--Help/command/cmake_policy.rst2
-rw-r--r--Help/command/ctest_submit.rst20
-rw-r--r--Help/command/ctest_update.rst3
-rw-r--r--Help/command/enable_testing.rst15
-rw-r--r--Help/command/execute_process.rst22
-rw-r--r--Help/command/export.rst11
-rw-r--r--Help/command/file.rst30
-rw-r--r--Help/command/find_package.rst27
-rw-r--r--Help/command/get_cmake_property.rst2
-rw-r--r--Help/command/get_target_property.rst2
-rw-r--r--Help/command/if.rst6
-rw-r--r--Help/command/include_external_msproject.rst4
-rw-r--r--Help/command/install.rst29
-rw-r--r--Help/command/install_files.rst2
-rw-r--r--Help/command/list.rst96
-rw-r--r--Help/command/math.rst2
-rw-r--r--Help/command/message.rst68
-rw-r--r--Help/command/output_required_files.rst6
-rw-r--r--Help/command/project.rst40
-rw-r--r--Help/command/set_property.rst4
-rw-r--r--Help/command/set_source_files_properties.rst2
-rw-r--r--Help/command/string.rst9
-rw-r--r--Help/command/target_link_libraries.rst2
-rw-r--r--Help/command/target_link_options.rst24
-rw-r--r--Help/command/try_compile.rst1
-rw-r--r--Help/command/use_mangled_mesa.rst2
-rw-r--r--Help/command/variable_requires.rst2
-rw-r--r--Help/cpack_gen/bundle.rst20
-rw-r--r--Help/cpack_gen/external.rst2
-rw-r--r--Help/cpack_gen/ifw.rst4
-rw-r--r--Help/cpack_gen/nsis.rst38
-rw-r--r--Help/cpack_gen/rpm.rst40
-rw-r--r--Help/dev/maint.rst6
-rw-r--r--Help/dev/review.rst75
-rw-r--r--Help/envvar/ASM_DIALECT.rst5
-rw-r--r--Help/envvar/ASM_DIALECTFLAGS.rst10
-rw-r--r--Help/envvar/CMAKE_GENERATOR.rst16
-rw-r--r--Help/envvar/CMAKE_GENERATOR_INSTANCE.rst7
-rw-r--r--Help/envvar/CMAKE_GENERATOR_PLATFORM.rst8
-rw-r--r--Help/envvar/CMAKE_GENERATOR_TOOLSET.rst8
-rw-r--r--Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst2
-rw-r--r--Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst2
-rw-r--r--Help/envvar/CTEST_PROGRESS_OUTPUT.rst2
-rw-r--r--Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst5
-rw-r--r--Help/envvar/PackageName_ROOT.rst2
-rw-r--r--Help/envvar/SWIFTC.rst11
-rw-r--r--Help/generator/CodeBlocks.rst6
-rw-r--r--Help/generator/CodeLite.rst6
-rw-r--r--Help/generator/Eclipse CDT4.rst2
-rw-r--r--Help/generator/Green Hills MULTI.rst12
-rw-r--r--Help/generator/Kate.rst8
-rw-r--r--Help/generator/MSYS Makefiles.rst3
-rw-r--r--Help/generator/MinGW Makefiles.rst3
-rw-r--r--Help/generator/Ninja.rst4
-rw-r--r--Help/generator/Sublime Text 2.rst10
-rw-r--r--Help/generator/Unix Makefiles.rst2
-rw-r--r--Help/generator/VS_TOOLSET_HOST_ARCH.txt4
-rw-r--r--Help/generator/Xcode.rst4
-rw-r--r--Help/manual/LINKS.txt2
-rw-r--r--Help/manual/OPTIONS_BUILD.txt43
-rw-r--r--Help/manual/ccmake.1.rst2
-rw-r--r--Help/manual/cmake-buildsystem.7.rst25
-rw-r--r--Help/manual/cmake-env-variables.7.rst5
-rw-r--r--Help/manual/cmake-file-api.7.rst2
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst200
-rw-r--r--Help/manual/cmake-gui.1.rst2
-rw-r--r--Help/manual/cmake-language.7.rst6
-rw-r--r--Help/manual/cmake-modules.7.rst1
-rw-r--r--Help/manual/cmake-packages.7.rst19
-rw-r--r--Help/manual/cmake-policies.7.rst14
-rw-r--r--Help/manual/cmake-properties.7.rst16
-rw-r--r--Help/manual/cmake-server.7.rst5
-rw-r--r--Help/manual/cmake-toolchains.7.rst20
-rw-r--r--Help/manual/cmake-variables.7.rst12
-rw-r--r--Help/manual/cmake.1.rst161
-rw-r--r--Help/manual/cpack.1.rst2
-rw-r--r--Help/manual/ctest.1.rst83
-rw-r--r--Help/module/CPackWIX.rst3
-rw-r--r--Help/module/FindEnvModules.rst1
-rw-r--r--Help/policy/CMP0000.rst24
-rw-r--r--Help/policy/CMP0001.rst16
-rw-r--r--Help/policy/CMP0002.rst12
-rw-r--r--Help/policy/CMP0003.rst10
-rw-r--r--Help/policy/CMP0004.rst11
-rw-r--r--Help/policy/CMP0005.rst10
-rw-r--r--Help/policy/CMP0006.rst26
-rw-r--r--Help/policy/CMP0007.rst10
-rw-r--r--Help/policy/CMP0008.rst19
-rw-r--r--Help/policy/CMP0009.rst16
-rw-r--r--Help/policy/CMP0010.rst10
-rw-r--r--Help/policy/CMP0011.rst31
-rw-r--r--Help/policy/CMP0012.rst27
-rw-r--r--Help/policy/CMP0013.rst6
-rw-r--r--Help/policy/CMP0014.rst16
-rw-r--r--Help/policy/CMP0015.rst20
-rw-r--r--Help/policy/CMP0016.rst9
-rw-r--r--Help/policy/CMP0017.rst16
-rw-r--r--Help/policy/CMP0018.rst35
-rw-r--r--Help/policy/CMP0019.rst8
-rw-r--r--Help/policy/CMP0020.rst22
-rw-r--r--Help/policy/CMP0021.rst19
-rw-r--r--Help/policy/CMP0022.rst30
-rw-r--r--Help/policy/CMP0023.rst22
-rw-r--r--Help/policy/CMP0024.rst19
-rw-r--r--Help/policy/CMP0025.rst10
-rw-r--r--Help/policy/CMP0026.rst23
-rw-r--r--Help/policy/CMP0027.rst28
-rw-r--r--Help/policy/CMP0028.rst26
-rw-r--r--Help/policy/CMP0037.rst23
-rw-r--r--Help/policy/CMP0038.rst8
-rw-r--r--Help/policy/CMP0039.rst8
-rw-r--r--Help/policy/CMP0041.rst8
-rw-r--r--Help/policy/CMP0042.rst4
-rw-r--r--Help/policy/CMP0043.rst8
-rw-r--r--Help/policy/CMP0044.rst8
-rw-r--r--Help/policy/CMP0045.rst8
-rw-r--r--Help/policy/CMP0046.rst8
-rw-r--r--Help/policy/CMP0047.rst10
-rw-r--r--Help/policy/CMP0048.rst14
-rw-r--r--Help/policy/CMP0049.rst8
-rw-r--r--Help/policy/CMP0050.rst8
-rw-r--r--Help/policy/CMP0052.rst7
-rw-r--r--Help/policy/CMP0055.rst8
-rw-r--r--Help/policy/CMP0056.rst6
-rw-r--r--Help/policy/CMP0060.rst6
-rw-r--r--Help/policy/CMP0061.rst2
-rw-r--r--Help/policy/CMP0062.rst2
-rw-r--r--Help/policy/CMP0065.rst2
-rw-r--r--Help/policy/CMP0066.rst2
-rw-r--r--Help/policy/CMP0067.rst2
-rw-r--r--Help/policy/CMP0071.rst2
-rw-r--r--Help/policy/CMP0082.rst2
-rw-r--r--Help/policy/CMP0089.rst30
-rw-r--r--Help/policy/CMP0090.rst27
-rw-r--r--Help/policy/CMP0091.rst47
-rw-r--r--Help/policy/CMP0092.rst38
-rw-r--r--Help/policy/CMP0093.rst24
-rw-r--r--Help/policy/CMP0094.rst22
-rw-r--r--Help/policy/DISALLOWED_COMMAND.txt8
-rw-r--r--Help/prop_cache/ADVANCED.rst2
-rw-r--r--Help/prop_cache/STRINGS.rst4
-rw-r--r--Help/prop_cache/TYPE.rst6
-rw-r--r--Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst21
-rw-r--r--Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst16
-rw-r--r--Help/prop_dir/EXCLUDE_FROM_ALL.rst20
-rw-r--r--Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst10
-rw-r--r--Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst2
-rw-r--r--Help/prop_dir/MACROS.rst2
-rw-r--r--Help/prop_dir/TESTS.rst3
-rw-r--r--Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst12
-rw-r--r--Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst4
-rw-r--r--Help/prop_dir/VS_STARTUP_PROJECT.rst2
-rw-r--r--Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst16
-rw-r--r--Help/prop_gbl/DISABLED_FEATURES.rst6
-rw-r--r--Help/prop_gbl/ENABLED_FEATURES.rst6
-rw-r--r--Help/prop_gbl/JOB_POOLS.rst5
-rw-r--r--Help/prop_gbl/USE_FOLDERS.rst4
-rw-r--r--Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst7
-rw-r--r--Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst4
-rw-r--r--Help/prop_inst/CPACK_NEVER_OVERWRITE.rst2
-rw-r--r--Help/prop_inst/CPACK_PERMANENT.rst2
-rw-r--r--Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst4
-rw-r--r--Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst4
-rw-r--r--Help/prop_inst/CPACK_WIX_ACL.rst2
-rw-r--r--Help/prop_sf/COMPILE_DEFINITIONS.rst10
-rw-r--r--Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst6
-rw-r--r--Help/prop_sf/EXTERNAL_OBJECT.rst2
-rw-r--r--Help/prop_sf/Fortran_FORMAT.rst7
-rw-r--r--Help/prop_sf/KEEP_EXTENSION.rst2
-rw-r--r--Help/prop_sf/LABELS.rst2
-rw-r--r--Help/prop_sf/LANGUAGE.rst3
-rw-r--r--Help/prop_sf/OBJECT_OUTPUTS.rst6
-rw-r--r--Help/prop_sf/SYMBOLIC.rst2
-rw-r--r--Help/prop_sf/Swift_DEPENDENCIES_FILE.rst5
-rw-r--r--Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst4
-rw-r--r--Help/prop_sf/VS_CSHARP_tagname.rst5
-rw-r--r--Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst3
-rw-r--r--Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst3
-rw-r--r--Help/prop_sf/VS_INCLUDE_IN_VSIX.rst6
-rw-r--r--Help/prop_sf/VS_SHADER_FLAGS.rst2
-rw-r--r--Help/prop_sf/VS_SHADER_TYPE.rst2
-rw-r--r--Help/prop_sf/VS_XAML_TYPE.rst7
-rw-r--r--Help/prop_sf/WRAP_EXCLUDE.rst9
-rw-r--r--Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst2
-rw-r--r--Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst4
-rw-r--r--Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst4
-rw-r--r--Help/prop_test/COST.rst13
-rw-r--r--Help/prop_test/DISABLED.rst14
-rw-r--r--Help/prop_test/ENVIRONMENT.rst2
-rw-r--r--Help/prop_test/MEASUREMENT.rst8
-rw-r--r--Help/prop_test/RUN_SERIAL.rst2
-rw-r--r--Help/prop_test/SKIP_RETURN_CODE.rst2
-rw-r--r--Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst23
-rw-r--r--Help/prop_tgt/AUTOGEN_BUILD_DIR.rst2
-rw-r--r--Help/prop_tgt/AUTOMOC.rst274
-rw-r--r--Help/prop_tgt/AUTORCC.rst51
-rw-r--r--Help/prop_tgt/AUTOUIC.rst87
-rw-r--r--Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst2
-rw-r--r--Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst4
-rw-r--r--Help/prop_tgt/DEBUG_POSTFIX.rst6
-rw-r--r--Help/prop_tgt/DEFINE_SYMBOL.rst4
-rw-r--r--Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst2
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_ALL.rst16
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst6
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst7
-rw-r--r--Help/prop_tgt/EXPORT_NAME.rst6
-rw-r--r--Help/prop_tgt/EchoString.rst4
-rw-r--r--Help/prop_tgt/FOLDER.rst6
-rw-r--r--Help/prop_tgt/FRAMEWORK.rst4
-rw-r--r--Help/prop_tgt/Fortran_FORMAT.rst6
-rw-r--r--Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst4
-rw-r--r--Help/prop_tgt/GENERATOR_FILE_NAME.rst2
-rw-r--r--Help/prop_tgt/GHS_INTEGRITY_APP.rst2
-rw-r--r--Help/prop_tgt/GNUtoMS.rst16
-rw-r--r--Help/prop_tgt/HAS_CXX.rst4
-rw-r--r--Help/prop_tgt/IMPORTED.rst4
-rw-r--r--Help/prop_tgt/IMPORTED_IMPLIB.rst4
-rw-r--r--Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst6
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst12
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst6
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst4
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION.rst25
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_NO_SONAME.rst6
-rw-r--r--Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORTED_SONAME.rst4
-rw-r--r--Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst2
-rw-r--r--Help/prop_tgt/IMPORT_PREFIX.rst6
-rw-r--r--Help/prop_tgt/IMPORT_SUFFIX.rst8
-rw-r--r--Help/prop_tgt/INCLUDE_DIRECTORIES.rst2
-rw-r--r--Help/prop_tgt/INSTALL_NAME_DIR.rst6
-rw-r--r--Help/prop_tgt/INSTALL_RPATH.rst4
-rw-r--r--Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst6
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst7
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst4
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst2
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/LINKER_LANGUAGE.rst2
-rw-r--r--Help/prop_tgt/LINK_DEPENDS.rst3
-rw-r--r--Help/prop_tgt/LINK_FLAGS_CONFIG.rst4
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst4
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst4
-rw-r--r--Help/prop_tgt/LINK_SEARCH_END_STATIC.rst11
-rw-r--r--Help/prop_tgt/LINK_SEARCH_START_STATIC.rst15
-rw-r--r--Help/prop_tgt/LOCATION.rst19
-rw-r--r--Help/prop_tgt/LOCATION_CONFIG.rst14
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt20
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst26
-rw-r--r--Help/prop_tgt/NO_SONAME.rst6
-rw-r--r--Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/POST_INSTALL_SCRIPT.rst8
-rw-r--r--Help/prop_tgt/PREFIX.rst2
-rw-r--r--Help/prop_tgt/PRE_INSTALL_SCRIPT.rst8
-rw-r--r--Help/prop_tgt/PRIVATE_HEADER.rst2
-rw-r--r--Help/prop_tgt/PUBLIC_HEADER.rst2
-rw-r--r--Help/prop_tgt/RESOURCE.rst13
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/SKIP_BUILD_RPATH.rst4
-rw-r--r--Help/prop_tgt/SUFFIX.rst2
-rw-r--r--Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst5
-rw-r--r--Help/prop_tgt/Swift_MODULE_DIRECTORY.rst10
-rw-r--r--Help/prop_tgt/Swift_MODULE_NAME.rst5
-rw-r--r--Help/prop_tgt/TYPE.rst6
-rw-r--r--Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst10
-rw-r--r--Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst46
-rw-r--r--Help/prop_tgt/VS_PACKAGE_REFERENCES.rst13
-rw-r--r--Help/prop_tgt/VS_PROJECT_IMPORT.rst8
-rw-r--r--Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst4
-rw-r--r--Help/prop_tgt/XCODE_GENERATE_SCHEME.rst39
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst7
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst2
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst2
-rw-r--r--Help/release/3.14.rst8
-rw-r--r--Help/release/3.15.rst347
-rw-r--r--Help/release/3.9.rst2
-rw-r--r--Help/release/index.rst1
-rw-r--r--Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst2
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING.rst5
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst6
-rw-r--r--Help/variable/CMAKE_CUDA_HOST_COMPILER.rst2
-rw-r--r--Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst6
-rw-r--r--Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst9
-rw-r--r--Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst15
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst27
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst3
-rw-r--r--Help/variable/CMAKE_FRAMEWORK.rst7
-rw-r--r--Help/variable/CMAKE_GENERATOR.rst5
-rw-r--r--Help/variable/CMAKE_GENERATOR_INSTANCE.rst7
-rw-r--r--Help/variable/CMAKE_GENERATOR_PLATFORM.rst3
-rw-r--r--Help/variable/CMAKE_GENERATOR_TOOLSET.rst3
-rw-r--r--Help/variable/CMAKE_JOB_POOL_LINK.rst2
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_ID.rst3
-rw-r--r--Help/variable/CMAKE_MAKE_PROGRAM.rst11
-rw-r--r--Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst27
-rw-r--r--Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst2
-rw-r--r--Help/variable/CMAKE_PROJECT_INCLUDE.rst9
-rw-r--r--Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst9
-rw-r--r--Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst10
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RULES.rst2
-rw-r--r--Help/variable/CMAKE_SOURCE_DIR.rst2
-rw-r--r--Help/variable/CMAKE_STAGING_PREFIX.rst10
-rw-r--r--Help/variable/CMAKE_SUPPRESS_REGENERATION.rst8
-rw-r--r--Help/variable/CMAKE_SYSROOT.rst4
-rw-r--r--Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst8
-rw-r--r--Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst8
-rw-r--r--Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst32
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst2
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst2
-rw-r--r--Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst2
-rw-r--r--Help/variable/CTEST_UPDATE_VERSION_ONLY.rst2
-rw-r--r--Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst5
-rw-r--r--Help/variable/PackageName_ROOT.rst2
-rw-r--r--Help/variable/XCODE_VERSION.rst4
-rw-r--r--Modules/AddFileDependencies.cmake16
-rw-r--r--Modules/BasicConfigVersion-AnyNewerVersion.cmake.in8
-rw-r--r--Modules/BasicConfigVersion-ExactVersion.cmake.in2
-rw-r--r--Modules/BasicConfigVersion-SameMajorVersion.cmake.in2
-rw-r--r--Modules/BasicConfigVersion-SameMinorVersion.cmake.in2
-rw-r--r--Modules/BundleUtilities.cmake126
-rw-r--r--Modules/CMakeASM_NASMInformation.cmake4
-rw-r--r--Modules/CMakeAddFortranSubdirectory.cmake8
-rw-r--r--Modules/CMakeAddNewLanguage.txt22
-rw-r--r--Modules/CMakeCCompiler.cmake.in1
-rw-r--r--Modules/CMakeCXXCompiler.cmake.in1
-rw-r--r--Modules/CMakeCheckCompilerFlagCommonPatterns.cmake49
-rw-r--r--Modules/CMakeCompilerIdDetection.cmake6
-rw-r--r--Modules/CMakeDetermineASMCompiler.cmake23
-rw-r--r--Modules/CMakeDetermineASM_MASMCompiler.cmake6
-rw-r--r--Modules/CMakeDetermineCCompiler.cmake7
-rw-r--r--Modules/CMakeDetermineCSharpCompiler.cmake2
-rw-r--r--Modules/CMakeDetermineCXXCompiler.cmake7
-rw-r--r--Modules/CMakeDetermineCompilerId.cmake131
-rw-r--r--Modules/CMakeDetermineSwiftCompiler.cmake49
-rw-r--r--Modules/CMakeDetermineVSServicePack.cmake52
-rw-r--r--Modules/CMakeExpandImportedTargets.cmake195
-rw-r--r--Modules/CMakeFindBinUtils.cmake21
-rw-r--r--Modules/CMakeFindCodeBlocks.cmake2
-rw-r--r--Modules/CMakeFindDependencyMacro.cmake51
-rw-r--r--Modules/CMakeFindSublimeText2.cmake2
-rw-r--r--Modules/CMakeForceCompiler.cmake33
-rw-r--r--Modules/CMakeFortranCompilerId.F.in7
-rw-r--r--Modules/CMakeJavaInformation.cmake4
-rw-r--r--Modules/CMakeNinjaFindMake.cmake2
-rw-r--r--Modules/CMakeParseImplicitIncludeInfo.cmake6
-rw-r--r--Modules/CMakePlatformId.h.in15
-rw-r--r--Modules/CMakePrintHelpers.cmake16
-rw-r--r--Modules/CMakePushCheckState.cmake66
-rw-r--r--Modules/CMakeRCInformation.cmake2
-rw-r--r--Modules/CMakeSwiftCompiler.cmake.in9
-rw-r--r--Modules/CMakeSwiftInformation.cmake71
-rw-r--r--Modules/CMakeSystemSpecificInformation.cmake2
-rw-r--r--Modules/CMakeTestSwiftCompiler.cmake7
-rw-r--r--Modules/CTestCoverageCollectGCOV.cmake40
-rw-r--r--Modules/CheckCCompilerFlag.cmake42
-rw-r--r--Modules/CheckCXXCompilerFlag.cmake46
-rw-r--r--Modules/CheckCXXSymbolExists.cmake2
-rw-r--r--Modules/CheckLanguage.cmake37
-rw-r--r--Modules/CheckPIESupported.cmake4
-rw-r--r--Modules/CheckStructHasMember.cmake46
-rw-r--r--Modules/CheckTypeSize.c.in2
-rw-r--r--Modules/Compiler/ARMCC-ASM.cmake2
-rw-r--r--Modules/Compiler/ARMClang-ASM.cmake9
-rw-r--r--Modules/Compiler/ARMClang-C-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/ARMClang-C.cmake15
-rw-r--r--Modules/Compiler/ARMClang-CXX-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/ARMClang-CXX.cmake3
-rw-r--r--Modules/Compiler/ARMClang-DetermineCompiler.cmake10
-rw-r--r--Modules/Compiler/ARMClang.cmake71
-rw-r--r--Modules/Compiler/AppleClang-C.cmake3
-rw-r--r--Modules/Compiler/AppleClang-CXX.cmake12
-rw-r--r--Modules/Compiler/CMakeCommonCompilerMacros.cmake56
-rw-r--r--Modules/Compiler/Clang-C.cmake6
-rw-r--r--Modules/Compiler/Clang-CXX.cmake18
-rw-r--r--Modules/Compiler/Cray-C.cmake3
-rw-r--r--Modules/Compiler/Cray-CXX.cmake3
-rw-r--r--Modules/Compiler/Cray-Fortran.cmake2
-rw-r--r--Modules/Compiler/CrayPrgEnv.cmake111
-rw-r--r--Modules/Compiler/GNU-C.cmake3
-rw-r--r--Modules/Compiler/GNU-CXX.cmake9
-rw-r--r--Modules/Compiler/GNU-FindBinUtils.cmake4
-rw-r--r--Modules/Compiler/IAR-ASM.cmake37
-rw-r--r--Modules/Compiler/IAR-C.cmake83
-rw-r--r--Modules/Compiler/IAR-CXX.cmake97
-rw-r--r--Modules/Compiler/IAR-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/IAR-FindBinUtils.cmake47
-rw-r--r--Modules/Compiler/IAR.cmake37
-rw-r--r--Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake16
-rw-r--r--Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake16
-rw-r--r--Modules/Compiler/Intel-C.cmake6
-rw-r--r--Modules/Compiler/Intel-CXX-FeatureTests.cmake2
-rw-r--r--Modules/Compiler/Intel-CXX.cmake10
-rw-r--r--Modules/Compiler/Intel-DetermineCompiler.cmake14
-rw-r--r--Modules/Compiler/MIPSpro-C.cmake1
-rw-r--r--Modules/Compiler/MIPSpro-CXX.cmake1
-rw-r--r--Modules/Compiler/MIPSpro-DetermineCompiler.cmake15
-rw-r--r--Modules/Compiler/MIPSpro-Fortran.cmake3
-rw-r--r--Modules/Compiler/MSVC-C.cmake19
-rw-r--r--Modules/Compiler/MSVC-CXX-FeatureTests.cmake6
-rw-r--r--Modules/Compiler/MSVC-CXX.cmake23
-rw-r--r--Modules/Compiler/NVIDIA-CUDA.cmake5
-rw-r--r--Modules/Compiler/PGI-C.cmake3
-rw-r--r--Modules/Compiler/PGI-CXX.cmake4
-rw-r--r--Modules/Compiler/SunPro-C.cmake3
-rw-r--r--Modules/Compiler/SunPro-CXX-FeatureTests.cmake8
-rw-r--r--Modules/Compiler/SunPro-CXX.cmake6
-rw-r--r--Modules/Compiler/XL-C-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/XL-C.cmake40
-rw-r--r--Modules/Compiler/XL-CXX-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/XL-CXX.cmake46
-rw-r--r--Modules/Compiler/XL.cmake22
-rw-r--r--Modules/Compiler/XLClang-C-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/XLClang-C.cmake20
-rw-r--r--Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/XLClang-CXX.cmake27
-rw-r--r--Modules/Compiler/XLClang.cmake22
-rw-r--r--Modules/ExternalProject.cmake175
-rw-r--r--Modules/FindALSA.cmake4
-rw-r--r--Modules/FindAVIFile.cmake2
-rw-r--r--Modules/FindArmadillo.cmake5
-rw-r--r--Modules/FindBISON.cmake6
-rw-r--r--Modules/FindBLAS.cmake58
-rw-r--r--Modules/FindBZip2.cmake64
-rw-r--r--Modules/FindBacktrace.cmake18
-rw-r--r--Modules/FindBoost.cmake779
-rw-r--r--Modules/FindBullet.cmake12
-rw-r--r--Modules/FindCUDA.cmake2
-rw-r--r--Modules/FindCURL.cmake8
-rw-r--r--Modules/FindCVS.cmake2
-rw-r--r--Modules/FindCups.cmake48
-rw-r--r--Modules/FindCurses.cmake2
-rw-r--r--Modules/FindCxxTest.cmake68
-rw-r--r--Modules/FindCygwin.cmake3
-rw-r--r--Modules/FindDCMTK.cmake2
-rw-r--r--Modules/FindDoxygen.cmake2
-rw-r--r--Modules/FindEXPAT.cmake1
-rw-r--r--Modules/FindEnvModules.cmake333
-rw-r--r--Modules/FindFLEX.cmake18
-rw-r--r--Modules/FindFLTK.cmake6
-rw-r--r--Modules/FindFLTK2.cmake3
-rw-r--r--Modules/FindGDAL.cmake2
-rw-r--r--Modules/FindGIF.cmake4
-rw-r--r--Modules/FindGLEW.cmake307
-rw-r--r--Modules/FindGLU.cmake1
-rw-r--r--Modules/FindGLUT.cmake2
-rw-r--r--Modules/FindGSL.cmake2
-rw-r--r--Modules/FindGTK.cmake5
-rw-r--r--Modules/FindGTK2.cmake11
-rw-r--r--Modules/FindGettext.cmake244
-rw-r--r--Modules/FindGnuTLS.cmake40
-rw-r--r--Modules/FindHDF5.cmake45
-rw-r--r--Modules/FindHSPELL.cmake2
-rw-r--r--Modules/FindICU.cmake12
-rw-r--r--Modules/FindIce.cmake4
-rw-r--r--Modules/FindIcotool.cmake4
-rw-r--r--Modules/FindImageMagick.cmake14
-rw-r--r--Modules/FindJPEG.cmake2
-rw-r--r--Modules/FindJasper.cmake2
-rw-r--r--Modules/FindKDE3.cmake213
-rw-r--r--Modules/FindKDE4.cmake60
-rw-r--r--Modules/FindLAPACK.cmake116
-rw-r--r--Modules/FindLATEX.cmake6
-rw-r--r--Modules/FindLTTngUST.cmake3
-rw-r--r--Modules/FindLibArchive.cmake3
-rw-r--r--Modules/FindLibLZMA.cmake14
-rw-r--r--Modules/FindLibXml2.cmake6
-rw-r--r--Modules/FindLibXslt.cmake3
-rw-r--r--Modules/FindLua.cmake219
-rw-r--r--Modules/FindLua50.cmake13
-rw-r--r--Modules/FindLua51.cmake10
-rw-r--r--Modules/FindMFC.cmake2
-rw-r--r--Modules/FindMPI.cmake75
-rw-r--r--Modules/FindMPI/libver_mpi.c1
-rw-r--r--Modules/FindMPI/test_mpi.c1
-rw-r--r--Modules/FindOpenAL.cmake20
-rw-r--r--Modules/FindOpenCL.cmake2
-rw-r--r--Modules/FindOpenGL.cmake6
-rw-r--r--Modules/FindOpenMP.cmake7
-rw-r--r--Modules/FindOpenSceneGraph.cmake24
-rw-r--r--Modules/FindPNG.cmake5
-rw-r--r--Modules/FindPhysFS.cmake6
-rw-r--r--Modules/FindPkgConfig.cmake243
-rw-r--r--Modules/FindPostgreSQL.cmake68
-rw-r--r--Modules/FindProducer.cmake12
-rw-r--r--Modules/FindProtobuf.cmake7
-rw-r--r--Modules/FindPython.cmake54
-rw-r--r--Modules/FindPython/Support.cmake1350
-rw-r--r--Modules/FindPython2.cmake56
-rw-r--r--Modules/FindPython3.cmake58
-rw-r--r--Modules/FindRuby.cmake313
-rw-r--r--Modules/FindSDL.cmake3
-rw-r--r--Modules/FindSDL_sound.cmake411
-rw-r--r--Modules/FindSWIG.cmake12
-rw-r--r--Modules/FindTIFF.cmake2
-rw-r--r--Modules/FindTclsh.cmake10
-rw-r--r--Modules/FindThreads.cmake44
-rw-r--r--Modules/FindUnixCommands.cmake5
-rw-r--r--Modules/FindVulkan.cmake5
-rw-r--r--Modules/FindZLIB.cmake4
-rw-r--r--Modules/Findosg.cmake2
-rw-r--r--Modules/FindosgDB.cmake32
-rw-r--r--Modules/Findosg_functions.cmake98
-rw-r--r--Modules/FortranCInterface/CMakeLists.txt5
-rw-r--r--Modules/GenerateExportHeader.cmake2
-rw-r--r--Modules/GetPrerequisites.cmake16
-rw-r--r--Modules/Internal/CPack/CPackNuGet.cmake2
-rw-r--r--Modules/Internal/CPack/CPackRPM.cmake13
-rw-r--r--Modules/Internal/FeatureTesting.cmake29
-rw-r--r--Modules/KDE3Macros.cmake453
-rw-r--r--Modules/MacroAddFileDependencies.cmake16
-rw-r--r--Modules/Platform/AIX-XL.cmake22
-rw-r--r--Modules/Platform/AIX-XLClang-C.cmake2
-rw-r--r--Modules/Platform/AIX-XLClang-CXX.cmake2
-rw-r--r--Modules/Platform/AIX-XLClang.cmake15
-rw-r--r--Modules/Platform/Android.cmake8
-rw-r--r--Modules/Platform/CrayLinuxEnvironment.cmake72
-rw-r--r--Modules/Platform/Darwin.cmake17
-rw-r--r--Modules/Platform/GHS-MULTI-Determine.cmake (renamed from Modules/Platform/GHS-MULTI-Initialize.cmake)29
-rw-r--r--Modules/Platform/SunOS.cmake12
-rw-r--r--Modules/Platform/Windows-Clang.cmake117
-rw-r--r--Modules/Platform/Windows-Intel-Fortran.cmake37
-rw-r--r--Modules/Platform/Windows-MSVC.cmake67
-rw-r--r--Modules/Platform/Windows-NVIDIA-CUDA.cmake34
-rw-r--r--Modules/ProcessorCount.cmake14
-rw-r--r--Modules/Qt4Macros.cmake108
-rw-r--r--Modules/UseEcos.cmake212
-rw-r--r--Modules/UseJava.cmake526
-rw-r--r--Modules/UseQt4.cmake5
-rw-r--r--Modules/UseSWIG.cmake13
-rw-r--r--Modules/WriteCompilerDetectionHeader.cmake2
-rw-r--r--Modules/ecos_clean.cmake12
-rw-r--r--README.rst34
-rw-r--r--Source/CMakeInstallSignTool.cmake.in51
-rw-r--r--Source/CMakeLists.txt65
-rw-r--r--Source/CMakeVersion.cmake4
-rw-r--r--Source/CMakeVersion.rc.in19
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx8
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx17
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.h3
-rw-r--r--Source/CPack/OSXScriptLauncher.cxx2
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx7
-rw-r--r--Source/CPack/bills-comments.txt68
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.cxx5
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx2
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx4
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.cxx5
-rw-r--r--Source/CPack/cmCPackGenerator.cxx21
-rw-r--r--Source/CPack/cmCPackGenerator.h5
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h3
-rw-r--r--Source/CPack/cmCPackLog.h3
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx41
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.cxx10
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx60
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.cxx4
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.cxx4
-rw-r--r--Source/CPack/cpack.cxx5
-rw-r--r--Source/CTest/cmCTestBZR.cxx5
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx17
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h2
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx11
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx70
-rw-r--r--Source/CTest/cmCTestBuildHandler.h2
-rw-r--r--Source/CTest/cmCTestCVS.cxx2
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx11
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx2
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx8
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx39
-rw-r--r--Source/CTest/cmCTestCurl.cxx9
-rw-r--r--Source/CTest/cmCTestCurl.h2
-rw-r--r--Source/CTest/cmCTestGIT.cxx4
-rw-r--r--Source/CTest/cmCTestGlobalVC.cxx5
-rw-r--r--Source/CTest/cmCTestGlobalVC.h2
-rw-r--r--Source/CTest/cmCTestHG.cxx5
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx2
-rw-r--r--Source/CTest/cmCTestLaunch.cxx2
-rw-r--r--Source/CTest/cmCTestLaunch.h3
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx5
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx14
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h6
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx25
-rw-r--r--Source/CTest/cmCTestP4.cxx16
-rw-r--r--Source/CTest/cmCTestRunTest.cxx123
-rw-r--r--Source/CTest/cmCTestRunTest.h5
-rw-r--r--Source/CTest/cmCTestSVN.cxx15
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx44
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx78
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h30
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx50
-rw-r--r--Source/CTest/cmCTestSubmitHandler.h4
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx5
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx6
-rw-r--r--Source/CTest/cmCTestTestHandler.h7
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx13
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx4
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx12
-rw-r--r--Source/CTest/cmCTestUploadCommand.h6
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx5
-rw-r--r--Source/CTest/cmCTestUploadHandler.h9
-rw-r--r--Source/CTest/cmCTestVC.cxx14
-rw-r--r--Source/CTest/cmCTestVC.h1
-rw-r--r--Source/CTest/cmProcess.cxx67
-rw-r--r--Source/CTest/cmProcess.h9
-rw-r--r--Source/Checks/cm_cxx17_check.cpp13
-rw-r--r--Source/CursesDialog/ccmake.cxx3
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.cxx2
-rw-r--r--Source/CursesDialog/cmCursesForm.h4
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx5
-rw-r--r--Source/CursesDialog/cmCursesMainForm.cxx145
-rw-r--r--Source/CursesDialog/cmCursesMainForm.h4
-rw-r--r--Source/LexerParser/cmCommandArgumentParser.cxx2
-rw-r--r--Source/QtDialog/CMakeLists.txt3
-rw-r--r--Source/QtDialog/CMakeSetup.cxx1
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx2
-rw-r--r--Source/QtDialog/FirstConfigure.cxx23
-rw-r--r--Source/QtDialog/QCMake.cxx47
-rw-r--r--Source/QtDialog/QCMake.h4
-rw-r--r--Source/QtDialog/RegexExplorer.cxx2
-rw-r--r--Source/cmAddCustomCommandCommand.cxx19
-rw-r--r--Source/cmAddCustomTargetCommand.cxx14
-rw-r--r--Source/cmAddDependenciesCommand.cxx9
-rw-r--r--Source/cmAddLibraryCommand.cxx7
-rw-r--r--Source/cmAddSubDirectoryCommand.cxx9
-rw-r--r--Source/cmAddTestCommand.cxx3
-rw-r--r--Source/cmAlgorithms.h117
-rw-r--r--Source/cmArchiveWrite.cxx20
-rw-r--r--Source/cmArchiveWrite.h6
-rw-r--r--Source/cmArgumentParser.cxx93
-rw-r--r--Source/cmArgumentParser.h143
-rw-r--r--Source/cmCMakeMinimumRequired.cxx2
-rw-r--r--Source/cmCMakePolicyCommand.cxx2
-rw-r--r--Source/cmCPluginAPI.cxx32
-rw-r--r--Source/cmCTest.cxx1148
-rw-r--r--Source/cmCTest.h266
-rw-r--r--Source/cmCacheManager.cxx10
-rw-r--r--Source/cmCacheManager.h24
-rw-r--r--Source/cmCallVisualStudioMacro.cxx42
-rw-r--r--Source/cmCallVisualStudioMacro.h12
-rw-r--r--Source/cmCommandArgumentsHelper.cxx233
-rw-r--r--Source/cmCommandArgumentsHelper.h194
-rw-r--r--Source/cmComputeLinkDepends.cxx19
-rw-r--r--Source/cmComputeLinkDepends.h3
-rw-r--r--Source/cmComputeLinkInformation.cxx6
-rw-r--r--Source/cmComputeTargetDepends.cxx6
-rw-r--r--Source/cmConditionEvaluator.cxx11
-rw-r--r--Source/cmConfigureFileCommand.cxx6
-rw-r--r--Source/cmCoreTryCompile.cxx30
-rw-r--r--Source/cmCreateTestSourceList.cxx3
-rw-r--r--Source/cmCustomCommand.cxx19
-rw-r--r--Source/cmCustomCommand.h5
-rw-r--r--Source/cmCustomCommandGenerator.cxx69
-rw-r--r--Source/cmCustomCommandGenerator.h7
-rw-r--r--Source/cmDepends.cxx191
-rw-r--r--Source/cmDepends.h29
-rw-r--r--Source/cmDependsC.cxx50
-rw-r--r--Source/cmDependsC.h5
-rw-r--r--Source/cmDependsFortran.cxx2
-rw-r--r--Source/cmDependsJava.cxx3
-rw-r--r--Source/cmDependsJava.h7
-rw-r--r--Source/cmDependsJavaParserHelper.cxx13
-rw-r--r--Source/cmDependsJavaParserHelper.h4
-rw-r--r--Source/cmDocumentationSection.h3
-rw-r--r--Source/cmELF.cxx3
-rw-r--r--Source/cmELF.h3
-rw-r--r--Source/cmExecProgramCommand.cxx34
-rw-r--r--Source/cmExecProgramCommand.h2
-rw-r--r--Source/cmExecuteProcessCommand.cxx339
-rw-r--r--Source/cmExportBuildFileGenerator.h3
-rw-r--r--Source/cmExportCommand.cxx131
-rw-r--r--Source/cmExportCommand.h24
-rw-r--r--Source/cmExportFileGenerator.cxx3
-rw-r--r--Source/cmExportLibraryDependenciesCommand.cxx8
-rw-r--r--Source/cmExportSet.h3
-rw-r--r--Source/cmExportSetMap.cxx2
-rw-r--r--Source/cmExportSetMap.h5
-rw-r--r--Source/cmExternalMakefileProjectGenerator.h10
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx82
-rw-r--r--Source/cmExtraCodeBlocksGenerator.h7
-rw-r--r--Source/cmExtraCodeLiteGenerator.cxx8
-rw-r--r--Source/cmExtraEclipseCDT4Generator.cxx7
-rw-r--r--Source/cmExtraKateGenerator.cxx6
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx10
-rw-r--r--Source/cmFLTKWrapUICommand.cxx10
-rw-r--r--Source/cmFileAPI.cxx63
-rw-r--r--Source/cmFileAPI.h5
-rw-r--r--Source/cmFileAPICodemodel.cxx4
-rw-r--r--Source/cmFileCommand.cxx1409
-rw-r--r--Source/cmFileCopier.cxx713
-rw-r--r--Source/cmFileCopier.h122
-rw-r--r--Source/cmFileInstaller.cxx350
-rw-r--r--Source/cmFileInstaller.h55
-rw-r--r--Source/cmFilePathChecksum.cxx2
-rw-r--r--Source/cmFileTime.cxx49
-rw-r--r--Source/cmFileTime.h130
-rw-r--r--Source/cmFileTimeCache.cxx62
-rw-r--r--Source/cmFileTimeCache.h56
-rw-r--r--Source/cmFileTimeComparison.cxx233
-rw-r--r--Source/cmFileTimeComparison.h42
-rw-r--r--Source/cmFileTimes.cxx127
-rw-r--r--Source/cmFileTimes.h40
-rw-r--r--Source/cmFindBase.cxx13
-rw-r--r--Source/cmFindCommon.cxx5
-rw-r--r--Source/cmFindPackageCommand.cxx152
-rw-r--r--Source/cmFindPackageCommand.h12
-rw-r--r--Source/cmForEachCommand.cxx7
-rw-r--r--Source/cmFortranParser.h3
-rw-r--r--Source/cmFortranParserImpl.cxx8
-rw-r--r--Source/cmFunctionCommand.cxx3
-rw-r--r--Source/cmGeneratedFileStream.cxx6
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx37
-rw-r--r--Source/cmGeneratorExpressionNode.cxx1228
-rw-r--r--Source/cmGeneratorExpressionNode.h4
-rw-r--r--Source/cmGeneratorExpressionParser.cxx11
-rw-r--r--Source/cmGeneratorTarget.cxx578
-rw-r--r--Source/cmGeneratorTarget.h44
-rw-r--r--Source/cmGetPipes.cxx48
-rw-r--r--Source/cmGetPipes.h8
-rw-r--r--Source/cmGhsMultiGpj.cxx10
-rw-r--r--Source/cmGhsMultiGpj.h9
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx539
-rw-r--r--Source/cmGhsMultiTargetGenerator.h34
-rw-r--r--Source/cmGlobVerificationManager.cxx8
-rw-r--r--Source/cmGlobVerificationManager.h12
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx19
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h19
-rw-r--r--Source/cmGlobalGenerator.cxx449
-rw-r--r--Source/cmGlobalGenerator.h64
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx569
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h105
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx20
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h17
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx9
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.h2
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx3
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.h2
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx20
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h17
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx1164
-rw-r--r--Source/cmGlobalNinjaGenerator.h121
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx196
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h20
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx147
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h22
-rw-r--r--Source/cmGlobalVisualStudio11Generator.cxx11
-rw-r--r--Source/cmGlobalVisualStudio11Generator.h4
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx74
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h25
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx43
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h12
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx45
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx6
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx18
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h17
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx248
-rw-r--r--Source/cmGlobalXCodeGenerator.h34
-rw-r--r--Source/cmGraphVizWriter.cxx26
-rw-r--r--Source/cmGraphVizWriter.h10
-rw-r--r--Source/cmHexFileConverter.cxx6
-rw-r--r--Source/cmHexFileConverter.h6
-rw-r--r--Source/cmIDEOptions.cxx6
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx7
-rw-r--r--Source/cmInstallCommand.cxx175
-rw-r--r--Source/cmInstallCommandArguments.cxx72
-rw-r--r--Source/cmInstallCommandArguments.h35
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx15
-rw-r--r--Source/cmInstallDirectoryGenerator.h2
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.cxx19
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.h2
-rw-r--r--Source/cmInstallExportGenerator.cxx5
-rw-r--r--Source/cmInstallExportGenerator.h2
-rw-r--r--Source/cmInstallFilesCommand.cxx10
-rw-r--r--Source/cmInstallFilesGenerator.cxx15
-rw-r--r--Source/cmInstallFilesGenerator.h2
-rw-r--r--Source/cmInstallGenerator.cxx11
-rw-r--r--Source/cmInstallGenerator.h2
-rw-r--r--Source/cmInstallProgramsCommand.cxx3
-rw-r--r--Source/cmInstallScriptGenerator.cxx4
-rw-r--r--Source/cmInstallScriptGenerator.h2
-rw-r--r--Source/cmInstallSubdirectoryGenerator.cxx3
-rw-r--r--Source/cmInstallSubdirectoryGenerator.h2
-rw-r--r--Source/cmInstallTargetGenerator.cxx106
-rw-r--r--Source/cmInstallTargetGenerator.h2
-rw-r--r--Source/cmInstallTargetsCommand.cxx8
-rw-r--r--Source/cmInstalledFile.h6
-rw-r--r--Source/cmJsonObjects.cxx4
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx91
-rw-r--r--Source/cmLinkLineDeviceComputer.h22
-rw-r--r--Source/cmListCommand.cxx139
-rw-r--r--Source/cmListCommand.h3
-rw-r--r--Source/cmListFileCache.cxx9
-rw-r--r--Source/cmLoadCommandCommand.cxx2
-rw-r--r--Source/cmLocalGenerator.cxx281
-rw-r--r--Source/cmLocalGenerator.h16
-rw-r--r--Source/cmLocalGhsMultiGenerator.cxx13
-rw-r--r--Source/cmLocalGhsMultiGenerator.h13
-rw-r--r--Source/cmLocalNinjaGenerator.cxx84
-rw-r--r--Source/cmLocalNinjaGenerator.h2
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx155
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h13
-rw-r--r--Source/cmLocalVisualStudio10Generator.h2
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx170
-rw-r--r--Source/cmLocalVisualStudio7Generator.h2
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx1
-rw-r--r--Source/cmLocalXCodeGenerator.h2
-rw-r--r--Source/cmMacroCommand.cxx3
-rw-r--r--Source/cmMakefile.cxx169
-rw-r--r--Source/cmMakefile.h60
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx84
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx148
-rw-r--r--Source/cmMakefileTargetGenerator.cxx121
-rw-r--r--Source/cmMakefileTargetGenerator.h12
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx9
-rw-r--r--Source/cmMessageCommand.cxx55
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.cxx20
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.h34
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx623
-rw-r--r--Source/cmNinjaNormalTargetGenerator.h9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx736
-rw-r--r--Source/cmNinjaTargetGenerator.h21
-rw-r--r--Source/cmNinjaTypes.h41
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx134
-rw-r--r--Source/cmOSXBundleGenerator.cxx8
-rw-r--r--Source/cmOrderDirectories.cxx6
-rw-r--r--Source/cmOrderDirectories.h2
-rw-r--r--Source/cmOutputConverter.h2
-rw-r--r--Source/cmOutputRequiredFilesCommand.cxx16
-rw-r--r--Source/cmParseArgumentsCommand.cxx204
-rw-r--r--Source/cmPolicies.cxx8
-rw-r--r--Source/cmPolicies.h32
-rw-r--r--Source/cmProjectCommand.cxx48
-rw-r--r--Source/cmProjectCommand.h1
-rw-r--r--Source/cmQTWrapCPPCommand.cxx15
-rw-r--r--Source/cmQTWrapUICommand.cxx15
-rw-r--r--Source/cmQtAutoGen.cxx202
-rw-r--r--Source/cmQtAutoGen.h95
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.cxx67
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.h41
-rw-r--r--Source/cmQtAutoGenInitializer.cxx999
-rw-r--r--Source/cmQtAutoGenInitializer.h100
-rw-r--r--Source/cmQtAutoGenerator.cxx613
-rw-r--r--Source/cmQtAutoGenerator.h247
-rw-r--r--Source/cmQtAutoGeneratorMocUic.cxx2042
-rw-r--r--Source/cmQtAutoGeneratorMocUic.h450
-rw-r--r--Source/cmQtAutoGeneratorRcc.cxx672
-rw-r--r--Source/cmQtAutoMocUic.cxx2193
-rw-r--r--Source/cmQtAutoMocUic.h576
-rw-r--r--Source/cmQtAutoRcc.cxx523
-rw-r--r--Source/cmQtAutoRcc.h (renamed from Source/cmQtAutoGeneratorRcc.h)73
-rw-r--r--Source/cmRST.cxx9
-rw-r--r--Source/cmRange.h239
-rw-r--r--Source/cmRemoveCommand.cxx10
-rw-r--r--Source/cmRulePlaceholderExpander.cxx35
-rw-r--r--Source/cmRulePlaceholderExpander.h5
-rw-r--r--Source/cmSearchPath.cxx4
-rw-r--r--Source/cmServer.cxx11
-rw-r--r--Source/cmServer.h4
-rw-r--r--Source/cmServerConnection.cxx4
-rw-r--r--Source/cmServerProtocol.cxx7
-rw-r--r--Source/cmSetCommand.cxx1
-rw-r--r--Source/cmSetPropertyCommand.cxx37
-rw-r--r--Source/cmSetTargetPropertiesCommand.cxx3
-rw-r--r--Source/cmSetTestsPropertiesCommand.cxx3
-rw-r--r--Source/cmSiteNameCommand.cxx5
-rw-r--r--Source/cmSourceFile.h11
-rw-r--r--Source/cmSourceGroupCommand.cxx6
-rw-r--r--Source/cmState.cxx19
-rw-r--r--Source/cmState.h5
-rw-r--r--Source/cmStateDirectory.cxx16
-rw-r--r--Source/cmStringCommand.cxx64
-rw-r--r--Source/cmStringCommand.h1
-rw-r--r--Source/cmSystemTools.cxx454
-rw-r--r--Source/cmSystemTools.h139
-rw-r--r--Source/cmTarget.cxx1052
-rw-r--r--Source/cmTarget.h236
-rw-r--r--Source/cmTargetPropertyComputer.cxx3
-rw-r--r--Source/cmTargetPropertyComputer.h2
-rw-r--r--Source/cmTest.h4
-rw-r--r--Source/cmTestGenerator.cxx17
-rw-r--r--Source/cmTryRunCommand.cxx34
-rw-r--r--Source/cmUVHandlePtr.cxx62
-rw-r--r--Source/cmUVHandlePtr.h40
-rw-r--r--Source/cmUVProcessChain.cxx395
-rw-r--r--Source/cmUVProcessChain.h100
-rw-r--r--Source/cmUVStreambuf.h219
-rw-r--r--Source/cmUseMangledMesaCommand.cxx22
-rw-r--r--Source/cmUseMangledMesaCommand.h3
-rw-r--r--Source/cmUtilitySourceCommand.cxx2
-rw-r--r--Source/cmUuid.cxx18
-rw-r--r--Source/cmUuid.h4
-rw-r--r--Source/cmVariableWatch.h3
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx220
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h6
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx15
-rw-r--r--Source/cmWorkerPool.cxx763
-rw-r--r--Source/cmWorkerPool.h226
-rw-r--r--Source/cmWorkingDirectory.h3
-rw-r--r--Source/cmXCodeScheme.cxx5
-rw-r--r--Source/cmXMLWriter.cxx2
-rw-r--r--Source/cmXMLWriter.h5
-rw-r--r--Source/cm_utf8.c29
-rw-r--r--Source/cm_utf8.h4
-rw-r--r--Source/cmake.cxx265
-rw-r--r--Source/cmake.h159
-rw-r--r--Source/cmakemain.cxx247
-rw-r--r--Source/cmakexbuild.cxx80
-rw-r--r--Source/cmcldeps.cxx2
-rw-r--r--Source/cmcmd.cxx335
-rw-r--r--Source/cmcmd.h14
-rw-r--r--Source/ctest.cxx4
-rw-r--r--Source/kwsys/CMakeLists.txt76
-rw-r--r--Source/kwsys/CommandLineArguments.hxx.in3
-rw-r--r--Source/kwsys/Configure.h.in37
-rw-r--r--Source/kwsys/Configure.hxx.in5
-rw-r--r--Source/kwsys/Directory.cxx4
-rw-r--r--Source/kwsys/DynamicLoader.cxx110
-rw-r--r--Source/kwsys/DynamicLoader.hxx.in15
-rw-r--r--Source/kwsys/Glob.cxx2
-rw-r--r--Source/kwsys/Glob.hxx.in14
-rw-r--r--Source/kwsys/ProcessWin32.c23
-rw-r--r--Source/kwsys/SystemInformation.cxx109
-rw-r--r--Source/kwsys/SystemInformation.hxx.in3
-rw-r--r--Source/kwsys/SystemTools.cxx533
-rw-r--r--Source/kwsys/SystemTools.hxx.in46
-rw-r--r--Source/kwsys/hashtable.hxx.in2
-rw-r--r--Source/kwsys/kwsysPlatformTestsCXX.cxx42
-rw-r--r--Source/kwsys/testConsoleBuf.cxx9
-rw-r--r--Source/kwsys/testDynamicLoader.cxx28
-rw-r--r--Source/kwsys/testDynloadImpl.c10
-rw-r--r--Source/kwsys/testDynloadImpl.h15
-rw-r--r--Source/kwsys/testDynloadUse.c15
-rw-r--r--Tests/AliasTarget/CMakeLists.txt2
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt1
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/consumer.c4
-rw-r--r--Tests/CMakeCommands/target_compile_options/CMakeLists.txt18
-rw-r--r--Tests/CMakeCommands/target_compile_options/consumer.cpp24
-rw-r--r--Tests/CMakeCommands/target_compile_options/main.cpp20
-rw-r--r--Tests/CMakeLib/CMakeLists.txt10
-rw-r--r--Tests/CMakeLib/testArgumentParser.cxx148
-rw-r--r--Tests/CMakeLib/testRST.expect4
-rw-r--r--Tests/CMakeLib/testRST.rst4
-rw-r--r--Tests/CMakeLib/testRange.cxx45
-rw-r--r--Tests/CMakeLib/testSystemTools.cxx17
-rw-r--r--Tests/CMakeLib/testUTF8.cxx104
-rw-r--r--Tests/CMakeLib/testUVProcessChain.cxx335
-rw-r--r--Tests/CMakeLib/testUVProcessChainHelper.cxx72
-rw-r--r--Tests/CMakeLib/testUVRAII.cxx50
-rw-r--r--Tests/CMakeLib/testUVStreambuf.cxx457
-rw-r--r--Tests/CMakeLists.txt107
-rw-r--r--Tests/CMakeOnly/CMakeLists.txt12
-rw-r--r--Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt2
-rw-r--r--Tests/CMakeOnly/CheckLanguage/CMakeLists.txt3
-rw-r--r--Tests/CMakeOnly/ProjectInclude/CMakeLists.txt2
-rw-r--r--Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt4
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt5
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBefore/include.cmake9
-rw-r--r--Tests/COnly/CMakeLists.txt2
-rw-r--r--Tests/CTestCoverageCollectGCOV/fakegcov.cmake21
-rw-r--r--Tests/CheckSwift.cmake61
-rw-r--r--Tests/CompileFeatures/CMakeLists.txt38
-rw-r--r--Tests/CompileFeatures/cxx_relaxed_constexpr.cpp3
-rw-r--r--Tests/CompileFeatures/genex_test.cpp15
-rw-r--r--Tests/CompileOptions/CMakeLists.txt3
-rw-r--r--Tests/CompileOptions/main.cpp3
-rw-r--r--Tests/Complex/CMakeLists.txt5
-rw-r--r--Tests/ComplexOneConfig/CMakeLists.txt5
-rw-r--r--Tests/Cuda/CMakeLists.txt1
-rw-r--r--Tests/Cuda/NotEnabled/CMakeLists.txt14
-rw-r--r--Tests/Cuda/NotEnabled/lib.cxx5
-rw-r--r--Tests/Cuda/NotEnabled/main.cxx9
-rw-r--r--Tests/CudaOnly/WithDefs/CMakeLists.txt2
-rw-r--r--Tests/CudaOnly/WithDefs/main.notcu8
-rw-r--r--Tests/EnforceConfig.cmake.in13
-rw-r--r--Tests/ExportImport/Export/Interface/CMakeLists.txt2
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt2
-rw-r--r--Tests/ExportImport/Import/Interface/CMakeLists.txt8
-rw-r--r--Tests/FindBoost/CMakeLists.txt3
-rw-r--r--Tests/FindBoost/Test/CMakeLists.txt1
-rw-r--r--Tests/FindCups/CMakeLists.txt10
-rw-r--r--Tests/FindCups/Test/CMakeLists.txt16
-rw-r--r--Tests/FindCups/Test/main.c12
-rw-r--r--Tests/FindEnvModules/CMakeLists.txt3
-rw-r--r--Tests/FindEnvModules/EnvModules.cmake35
-rw-r--r--Tests/FindGLEW/CMakeLists.txt10
-rw-r--r--Tests/FindGLEW/Test/CMakeLists.txt18
-rw-r--r--Tests/FindGLEW/Test/main.cpp8
-rw-r--r--Tests/FindIconv/Test/CMakeLists.txt2
-rw-r--r--Tests/FindPackageTest/CMakeLists.txt123
-rw-r--r--Tests/FindPackageTest/PreferConfig/ABCConfig.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfig/FindABC.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake1
-rw-r--r--Tests/FindPython/CMakeLists.txt65
-rw-r--r--Tests/FindPython/Python/CMakeLists.txt3
-rw-r--r--Tests/FindPython/Python2/CMakeLists.txt3
-rw-r--r--Tests/FindPython/Python2Embedded/CMakeLists.txt29
-rw-r--r--Tests/FindPython/Python3/CMakeLists.txt3
-rw-r--r--Tests/FindPython/Python3Embedded/CMakeLists.txt29
-rw-r--r--Tests/FindPython/VirtualEnv/CMakeLists.txt42
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake6
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake16
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake7
-rw-r--r--Tests/FindPython/display_time.c36
-rw-r--r--Tests/FindPython/display_time.h2
-rw-r--r--Tests/FindPython/main.c7
-rw-r--r--Tests/Fortran/CMakeLists.txt2
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt77
-rw-r--r--Tests/GeneratorExpression/check-part3.cmake5
-rw-r--r--Tests/GeneratorExpression/check-part4.cmake15
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt110
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in108
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/exe1.c5
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt12
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt11
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c8
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h3
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt28
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in16
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in7
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt14
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt8
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt2
-rw-r--r--Tests/GhsMulti/GhsMultiPlatform/file1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt6
-rw-r--r--Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt2
-rw-r--r--Tests/IncludeDirectories/CMakeLists.txt2
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt16
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp3
-rw-r--r--Tests/MSVCRuntimeLibrary/CMakeLists.txt71
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt50
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/verify.F901
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.c1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.cu1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.cxx1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.h29
-rw-r--r--Tests/MakeClean/ToClean/CMakeLists.txt128
-rw-r--r--Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt17
-rw-r--r--Tests/MakeClean/check_clean.c.in2
-rw-r--r--Tests/Module/FindDependency/CMakeLists.txt4
-rw-r--r--Tests/Module/FindDependency/main.cpp12
-rw-r--r--Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake14
-rw-r--r--Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake7
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt21
-rw-r--r--Tests/ObjectLibrary/CMakeLists.txt10
-rw-r--r--Tests/Plugin/CMakeLists.txt18
-rw-r--r--Tests/Preprocess/CMakeLists.txt14
-rw-r--r--Tests/Preprocess/preprocess.c3
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt3
-rw-r--r--Tests/QtAutogen/ManySources/CMakeLists.txt35
-rw-r--r--Tests/QtAutogen/ManySources/data.qrc.in7
-rw-r--r--Tests/QtAutogen/ManySources/item.cpp.in27
-rw-r--r--Tests/QtAutogen/ManySources/item.h.in15
-rw-r--r--Tests/QtAutogen/ManySources/main.cpp.in7
-rw-r--r--Tests/QtAutogen/ManySources/object.h.in15
-rw-r--r--Tests/QtAutogen/ManySources/view.ui.in24
-rw-r--r--Tests/QtAutogen/RerunMocBasic/CMakeLists.txt98
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt144
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt33
-rw-r--r--Tests/QtAutogen/RerunRccDepends/CMakeLists.txt175
-rw-r--r--Tests/QtAutogen/SameName/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/Tests.cmake1
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt4
-rw-r--r--Tests/RunCMake/CMakeLists.txt22
-rw-r--r--Tests/RunCMake/CTestCommandLine/show_only_json_check.pycbin1829 -> 1829 bytes
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt (renamed from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt)0
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt (renamed from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt)2
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt (renamed from Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-result.txt)0
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-stdout.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-three-directories-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-stderr.txt (renamed from Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-stderr.txt)0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-three-directories-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-three-directories-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt5
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-ninja-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-unset-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-warnings-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt7
-rw-r--r--Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake136
-rw-r--r--Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake15
-rw-r--r--Tests/RunCMake/CommandLine/install-bad-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-no-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-no-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-options-to-vars-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake34
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-file-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-without-action-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/gnutar-gz.cmake4
-rw-r--r--Tests/RunCMake/CommandLineTar/pax-zstd.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/pax.cmake4
-rw-r--r--Tests/RunCMake/CommandLineTar/roundtrip.cmake14
-rw-r--r--Tests/RunCMake/CommandLineTar/test-file.txt0
-rw-r--r--Tests/RunCMake/CommandLineTar/without-files-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/zip-filtered.cmake28
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake3
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake14
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake9
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/FileAPI/check_index.pycbin8146 -> 8146 bytes
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt3
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-NEW.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-OLD-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-OLD.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-UNSET-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-UNSET.cmake1
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage-stdout.txt5
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfig.cmake140
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfigVersion.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/BoostDetectToolset-1.70.0.cmake1
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config.cmake20
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfig.cmake26
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfig.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfig.cmake24
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_date_time.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_mpi_python.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python_release.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfig.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound-stderr.txt (renamed from Tests/RunCMake/add_subdirectory/ExcludeFromAll-build-sub-stderr.txt)0
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CommonResults-stdout.txt13
-rw-r--r--Tests/RunCMake/FindBoost/CommonResults.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/ConfigMode.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/ConfigModeNotFound.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix-stdout.txt34
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-NoHeaderTarget.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined-stdout.txt34
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars.cmake28
-rw-r--r--Tests/RunCMake/FindBoost/MissingTarget-stdout.txt22
-rw-r--r--Tests/RunCMake/FindBoost/MissingTarget.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/chrono.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/config.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/system/config.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/timer.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_chrono-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_system-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_timer-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/ModuleMode.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/ModuleModeNotFound.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/RunCMakeTest.cmake23
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc12
-rw-r--r--Tests/RunCMake/Framework/FrameworkLayout.cmake5
-rw-r--r--Tests/RunCMake/Framework/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-unknown-lang.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake9
-rw-r--r--Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/ResultValidator.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake34
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake106
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake135
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake49
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake49
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake49
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake49
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake18
-rw-r--r--Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME-check.cmake7
-rw-r--r--Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake16
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt1
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake37
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/empty.c0
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake12
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/C.cmake27
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/CXX.cmake27
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/a.c0
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/a.cxx0
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandJobPool-check.cmake8
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandJobPool.cmake17
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal-stderr.txt9
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal.cmake2
-rw-r--r--Tests/RunCMake/Ninja/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/Ninja/greeting.c1
-rw-r--r--Tests/RunCMake/Ninja/greeting2.c1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake32
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt4
-rw-r--r--Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/ObjectLibrary/check_object_files.cmake17
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input40
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input44
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output1
-rw-r--r--Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/RunCMake.cmake18
-rw-r--r--Tests/RunCMake/Swift/E.swift2
-rw-r--r--Tests/RunCMake/Swift/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed-result.txt1
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed-stderr.txt4
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed.cmake4
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall2.cmake3
-rw-r--r--Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt9
-rw-r--r--Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake4
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt4
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-common.cmake2
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake36
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary.cmake20
-rw-r--r--Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake38
-rw-r--r--Tests/RunCMake/VS10Project/VsJustMyCode.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsPackageReferences-check.cmake39
-rw-r--r--Tests/RunCMake/VS10Project/VsPackageReferences.cmake4
-rw-r--r--Tests/RunCMake/VS10Project/VsProjectImport-check.cmake28
-rw-r--r--Tests/RunCMake/VS10Project/VsProjectImport.cmake11
-rw-r--r--Tests/RunCMake/VS10Project/empty.c0
-rw-r--r--Tests/RunCMake/VS10Project/empty.cxx0
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake59
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake3
-rw-r--r--Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt2
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt4
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt4
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt4
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake9
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake3
-rw-r--r--Tests/RunCMake/add_executable/NoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake8
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt23
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake32
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake73
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/subinc.cpp4
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/zot.cpp4
-rw-r--r--Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake36
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake133
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/ctest_submit/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/ctest_update/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_update/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/ctest_update/UpdateActualVersion-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_update/UpdateChangeId-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_update/test.cmake.in18
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-stderr.txt5
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-stdout.txt12
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand.cmake41
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-stderr.txt5
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-stdout.txt12
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand3-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand3-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/export/AppendExport-stderr.txt2
-rw-r--r--Tests/RunCMake/export/Empty.cmake1
-rw-r--r--Tests/RunCMake/export/OldIface-stderr.txt3
-rw-r--r--Tests/RunCMake/export/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN.cmake168
-rw-r--r--Tests/RunCMake/file/REMOVE-empty-stderr.txt11
-rw-r--r--Tests/RunCMake/file/REMOVE-empty.cmake2
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake6
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults.cmake8
-rw-r--r--Tests/RunCMake/install/obj2.h6
-rw-r--r--Tests/RunCMake/interface_library/whitelist.cmake9
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/POP_BACK.cmake79
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/POP_FRONT.cmake92
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/PREPEND.cmake33
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake5
-rw-r--r--Tests/RunCMake/list/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/message/RunCMakeTest.cmake42
-rw-r--r--Tests/RunCMake/message/message-all-loglevels.cmake10
-rw-r--r--Tests/RunCMake/message/message-loglevel-debug-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-debug-stdout.txt3
-rw-r--r--Tests/RunCMake/message/message-loglevel-default-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-default-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-invalid-result.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-invalid-stderr.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-notice-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-status-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-status-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-trace-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-trace-stdout.txt4
-rw-r--r--Tests/RunCMake/message/message-loglevel-verbose-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-verbose-stdout.txt2
-rw-r--r--Tests/RunCMake/message/message-loglevel-warning-stderr.txt9
-rw-r--r--Tests/RunCMake/project_injected/CMP0048-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/pseudo_emulator_custom_command_arg.c30
-rw-r--r--Tests/RunCMake/string/Repeat.cmake45
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount-result.txt1
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount-stderr.txt4
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount.cmake1
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/try_compile/CMP0066-stderr.txt13
-rw-r--r--Tests/RunCMake/try_compile/LinkOptions.cmake4
-rw-r--r--Tests/RunCMake/try_run/LinkOptions.cmake4
-rw-r--r--Tests/SourceGroups/CMakeLists.txt8
-rw-r--r--Tests/StagingPrefix/CMakeLists.txt11
-rw-r--r--Tests/SwiftMix/CMain.c6
-rw-r--r--Tests/SwiftMix/CMakeLists.txt1
-rw-r--r--Tests/SwiftMix/ObjCMain.m2
-rw-r--r--Tests/SwiftMix/SwiftMain.swift2
-rw-r--r--Tests/Tutorial/Complete/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Consumer/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step10/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step11/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step2/CMakeLists.txt4
-rw-r--r--Tests/Tutorial/Step2/directions.txt3
-rw-r--r--Tests/Tutorial/Step3/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step4/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step5/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step6/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step7/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step8/CMakeLists.txt3
-rw-r--r--Tests/Tutorial/Step9/CMakeLists.txt3
-rw-r--r--Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt35
-rw-r--r--Tests/UseSWIG/CMakeLists.txt12
-rw-r--r--Tests/UseSWIG/ModuleName/CMakeLists.txt2
-rw-r--r--Tests/UseSWIG/ModuleVersion2/CMakeLists.txt4
-rw-r--r--Tests/UseSWIG/MultipleModules/CMakeLists.txt2
-rw-r--r--Tests/UseSWIG/MultiplePython/CMakeLists.txt4
-rw-r--r--Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt4
-rw-r--r--Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt4
-rw-r--r--Tests/WarnUnusedCliUnused/CMakeLists.txt8
-rw-r--r--Utilities/Doxygen/CMakeLists.txt2
-rw-r--r--Utilities/IWYU/mapping.imp1
-rw-r--r--Utilities/Release/linux64_release.cmake1
-rw-r--r--Utilities/Release/osx_release.cmake1
-rwxr-xr-xUtilities/Release/push.bash70
-rwxr-xr-xUtilities/Release/release_cmake.sh.in2
-rw-r--r--Utilities/Release/upload_release.cmake39
-rw-r--r--Utilities/Release/win32_release.cmake15
-rw-r--r--Utilities/Release/win64_release.cmake15
-rwxr-xr-xUtilities/Scripts/update-curl.bash2
-rwxr-xr-xUtilities/Scripts/update-expat.bash2
-rw-r--r--Utilities/Scripts/update-third-party.bash24
-rwxr-xr-xUtilities/Scripts/update-zstd.bash36
-rw-r--r--Utilities/Sphinx/CMakeLists.txt2
-rw-r--r--Utilities/cmThirdParty.h.in1
-rw-r--r--Utilities/cm_zstd.h14
-rw-r--r--Utilities/cmcompress/CMakeLists.txt5
-rw-r--r--Utilities/cmcompress/Copyright.txt34
-rw-r--r--Utilities/cmcompress/cmcompress.c551
-rw-r--r--Utilities/cmcompress/cmcompress.h195
-rw-r--r--Utilities/cmcompress/compress.c.original1308
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c52
-rw-r--r--Utilities/cmcurl/CMake/FindGSS.cmake4
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake67
-rw-r--r--Utilities/cmcurl/CMakeLists.txt75
-rw-r--r--Utilities/cmcurl/COPYING2
-rw-r--r--Utilities/cmcurl/include/curl/curl.h66
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h12
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h14
-rw-r--r--Utilities/cmcurl/include/curl/urlapi.h7
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc19
-rw-r--r--Utilities/cmcurl/lib/altsvc.c569
-rw-r--r--Utilities/cmcurl/lib/altsvc.h77
-rw-r--r--Utilities/cmcurl/lib/amigaos.c32
-rw-r--r--Utilities/cmcurl/lib/amigaos.h10
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c157
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c70
-rw-r--r--Utilities/cmcurl/lib/asyn.h36
-rw-r--r--Utilities/cmcurl/lib/base64.c33
-rw-r--r--Utilities/cmcurl/lib/conncache.c38
-rw-r--r--Utilities/cmcurl/lib/conncache.h8
-rw-r--r--Utilities/cmcurl/lib/connect.c114
-rw-r--r--Utilities/cmcurl/lib/connect.h9
-rw-r--r--Utilities/cmcurl/lib/cookie.c202
-rw-r--r--Utilities/cmcurl/lib/cookie.h13
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c32
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.h13
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake10
-rw-r--r--Utilities/cmcurl/lib/curl_endian.c10
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.c15
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.c55
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.h (renamed from Utilities/cmcurl/lib/vtls/axtls.h)18
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c6
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.h16
-rw-r--r--Utilities/cmcurl/lib/curl_md4.h4
-rw-r--r--Utilities/cmcurl/lib/curl_md5.h10
-rw-r--r--Utilities/cmcurl/lib/curl_memory.h4
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c12
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c69
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.h4
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c86
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.h11
-rw-r--r--Utilities/cmcurl/lib/curl_path.c6
-rw-r--r--Utilities/cmcurl/lib/curl_printf.h16
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c9
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c40
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h29
-rw-r--r--Utilities/cmcurl/lib/curlx.h11
-rw-r--r--Utilities/cmcurl/lib/dict.c11
-rw-r--r--Utilities/cmcurl/lib/doh.c127
-rw-r--r--Utilities/cmcurl/lib/doh.h10
-rw-r--r--Utilities/cmcurl/lib/easy.c111
-rw-r--r--Utilities/cmcurl/lib/escape.c2
-rw-r--r--Utilities/cmcurl/lib/file.c29
-rw-r--r--Utilities/cmcurl/lib/fileinfo.c5
-rw-r--r--Utilities/cmcurl/lib/formdata.c14
-rw-r--r--Utilities/cmcurl/lib/formdata.h11
-rw-r--r--Utilities/cmcurl/lib/ftp.c103
-rw-r--r--Utilities/cmcurl/lib/ftp.h3
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c7
-rw-r--r--Utilities/cmcurl/lib/getinfo.c8
-rw-r--r--Utilities/cmcurl/lib/gopher.c28
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c8
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c11
-rw-r--r--Utilities/cmcurl/lib/hostip.c153
-rw-r--r--Utilities/cmcurl/lib/hostip.h19
-rw-r--r--Utilities/cmcurl/lib/hostip4.c4
-rw-r--r--Utilities/cmcurl/lib/hostip6.c14
-rw-r--r--Utilities/cmcurl/lib/http.c492
-rw-r--r--Utilities/cmcurl/lib/http.h9
-rw-r--r--Utilities/cmcurl/lib/http2.c76
-rw-r--r--Utilities/cmcurl/lib/http2.h7
-rw-r--r--Utilities/cmcurl/lib/http_digest.c5
-rw-r--r--Utilities/cmcurl/lib/http_digest.h12
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.c132
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.h8
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c40
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.h10
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c4
-rw-r--r--Utilities/cmcurl/lib/if2ip.c59
-rw-r--r--Utilities/cmcurl/lib/if2ip.h6
-rw-r--r--Utilities/cmcurl/lib/imap.c41
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c12
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c3
-rw-r--r--Utilities/cmcurl/lib/ldap.c22
-rw-r--r--Utilities/cmcurl/lib/libcurl.rc12
-rw-r--r--Utilities/cmcurl/lib/md4.c114
-rw-r--r--Utilities/cmcurl/lib/md5.c174
-rw-r--r--Utilities/cmcurl/lib/memdebug.c154
-rw-r--r--Utilities/cmcurl/lib/memdebug.h123
-rw-r--r--Utilities/cmcurl/lib/mime.c94
-rw-r--r--Utilities/cmcurl/lib/mime.h27
-rw-r--r--Utilities/cmcurl/lib/mprintf.c2
-rw-r--r--Utilities/cmcurl/lib/multi.c916
-rw-r--r--Utilities/cmcurl/lib/multihandle.h48
-rw-r--r--Utilities/cmcurl/lib/multiif.h33
-rw-r--r--Utilities/cmcurl/lib/netrc.c16
-rw-r--r--Utilities/cmcurl/lib/netrc.h11
-rw-r--r--Utilities/cmcurl/lib/non-ascii.c4
-rw-r--r--Utilities/cmcurl/lib/openldap.c13
-rw-r--r--Utilities/cmcurl/lib/parsedate.c41
-rw-r--r--Utilities/cmcurl/lib/pingpong.c9
-rw-r--r--Utilities/cmcurl/lib/pingpong.h7
-rw-r--r--Utilities/cmcurl/lib/pipeline.c404
-rw-r--r--Utilities/cmcurl/lib/pipeline.h56
-rw-r--r--Utilities/cmcurl/lib/pop3.c32
-rw-r--r--Utilities/cmcurl/lib/progress.c150
-rw-r--r--Utilities/cmcurl/lib/rand.h7
-rw-r--r--Utilities/cmcurl/lib/rtsp.c35
-rw-r--r--Utilities/cmcurl/lib/security.c19
-rw-r--r--Utilities/cmcurl/lib/sendf.c63
-rw-r--r--Utilities/cmcurl/lib/setopt.c358
-rw-r--r--Utilities/cmcurl/lib/sigpipe.h5
-rw-r--r--Utilities/cmcurl/lib/smb.c9
-rw-r--r--Utilities/cmcurl/lib/smtp.c33
-rw-r--r--Utilities/cmcurl/lib/socks.c26
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c6
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c11
-rw-r--r--Utilities/cmcurl/lib/splay.c4
-rw-r--r--Utilities/cmcurl/lib/ssh-libssh.c90
-rw-r--r--Utilities/cmcurl/lib/ssh.c92
-rw-r--r--Utilities/cmcurl/lib/strerror.c44
-rw-r--r--Utilities/cmcurl/lib/strerror.h11
-rw-r--r--Utilities/cmcurl/lib/system_win32.c82
-rw-r--r--Utilities/cmcurl/lib/system_win32.h6
-rw-r--r--Utilities/cmcurl/lib/telnet.c34
-rw-r--r--Utilities/cmcurl/lib/tftp.c46
-rw-r--r--Utilities/cmcurl/lib/timeval.c46
-rw-r--r--Utilities/cmcurl/lib/timeval.h4
-rw-r--r--Utilities/cmcurl/lib/transfer.c361
-rw-r--r--Utilities/cmcurl/lib/transfer.h20
-rw-r--r--Utilities/cmcurl/lib/url.c969
-rw-r--r--Utilities/cmcurl/lib/url.h14
-rw-r--r--Utilities/cmcurl/lib/urlapi-int.h12
-rw-r--r--Utilities/cmcurl/lib/urlapi.c230
-rw-r--r--Utilities/cmcurl/lib/urldata.h634
-rw-r--r--Utilities/cmcurl/lib/vauth/cleartext.c40
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c15
-rw-r--r--Utilities/cmcurl/lib/vauth/digest_sspi.c4
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_gssapi.c6
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_sspi.c6
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c262
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm_sspi.c51
-rw-r--r--Utilities/cmcurl/lib/vauth/oauth2.c56
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_gssapi.c14
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_sspi.c56
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.c42
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.h20
-rw-r--r--Utilities/cmcurl/lib/version.c55
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.c741
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.c42
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c20
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c82
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c45
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.c8
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c90
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c309
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.c17
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl_threadlock.c59
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl_threadlock.h9
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c345
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h4
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c55
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c (renamed from Utilities/cmcurl/lib/vtls/darwinssl.c)194
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.h (renamed from Utilities/cmcurl/lib/vtls/darwinssl.h)14
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c67
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h9
-rw-r--r--Utilities/cmcurl/lib/warnless.c40
-rw-r--r--Utilities/cmcurl/lib/warnless.h6
-rw-r--r--Utilities/cmcurl/lib/wildcard.c6
-rw-r--r--Utilities/cmcurl/lib/wildcard.h10
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c269
-rw-r--r--Utilities/cmexpat/CMakeLists.txt2
-rw-r--r--Utilities/cmexpat/ConfigureChecks.cmake35
-rw-r--r--Utilities/cmexpat/README.md55
-rw-r--r--Utilities/cmexpat/expat_config.h.cmake30
-rw-r--r--Utilities/cmexpat/lib/ascii.h32
-rw-r--r--Utilities/cmexpat/lib/asciitab.h32
-rw-r--r--Utilities/cmexpat/lib/expat.h36
-rw-r--r--Utilities/cmexpat/lib/expat_external.h92
-rw-r--r--Utilities/cmexpat/lib/iasciitab.h32
-rw-r--r--Utilities/cmexpat/lib/internal.h36
-rw-r--r--Utilities/cmexpat/lib/latin1tab.h32
-rw-r--r--Utilities/cmexpat/lib/loadlibrary.c4
-rw-r--r--Utilities/cmexpat/lib/nametab.h32
-rw-r--r--Utilities/cmexpat/lib/siphash.h17
-rw-r--r--Utilities/cmexpat/lib/utf8tab.h33
-rw-r--r--Utilities/cmexpat/lib/winconfig.h41
-rw-r--r--Utilities/cmexpat/lib/xmlparse.c2715
-rw-r--r--Utilities/cmexpat/lib/xmlrole.c32
-rw-r--r--Utilities/cmexpat/lib/xmlrole.h32
-rw-r--r--Utilities/cmexpat/lib/xmltok.c90
-rw-r--r--Utilities/cmexpat/lib/xmltok.h37
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.c115
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.h31
-rw-r--r--Utilities/cmexpat/lib/xmltok_ns.c33
-rw-r--r--Utilities/cmjsoncpp/CMakeLists.txt2
-rw-r--r--Utilities/cmjsoncpp/include/json/config.h17
-rw-r--r--Utilities/cmlibarchive/CMakeLists.txt8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_version_details.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c2
-rw-r--r--Utilities/cmliblzma/CMakeLists.txt2
-rw-r--r--Utilities/cmlibrhash/CMakeLists.txt2
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt2
-rw-r--r--Utilities/cmlibuv/src/unix/atomic-ops.h4
-rw-r--r--Utilities/cmzlib/CMakeLists.txt2
-rw-r--r--Utilities/cmzstd/CMakeLists.txt47
-rw-r--r--Utilities/cmzstd/LICENSE30
-rw-r--r--Utilities/cmzstd/README.md167
-rw-r--r--Utilities/cmzstd/lib/common/bitstream.h455
-rw-r--r--Utilities/cmzstd/lib/common/compiler.h140
-rw-r--r--Utilities/cmzstd/lib/common/cpu.h215
-rw-r--r--Utilities/cmzstd/lib/common/debug.c44
-rw-r--r--Utilities/cmzstd/lib/common/debug.h134
-rw-r--r--Utilities/cmzstd/lib/common/entropy_common.c236
-rw-r--r--Utilities/cmzstd/lib/common/error_private.c54
-rw-r--r--Utilities/cmzstd/lib/common/error_private.h76
-rw-r--r--Utilities/cmzstd/lib/common/fse.h708
-rw-r--r--Utilities/cmzstd/lib/common/fse_decompress.c309
-rw-r--r--Utilities/cmzstd/lib/common/huf.h358
-rw-r--r--Utilities/cmzstd/lib/common/mem.h380
-rw-r--r--Utilities/cmzstd/lib/common/pool.c340
-rw-r--r--Utilities/cmzstd/lib/common/pool.h84
-rw-r--r--Utilities/cmzstd/lib/common/threading.c75
-rw-r--r--Utilities/cmzstd/lib/common/threading.h123
-rw-r--r--Utilities/cmzstd/lib/common/xxhash.c876
-rw-r--r--Utilities/cmzstd/lib/common/xxhash.h305
-rw-r--r--Utilities/cmzstd/lib/common/zstd_common.c83
-rw-r--r--Utilities/cmzstd/lib/common/zstd_errors.h93
-rw-r--r--Utilities/cmzstd/lib/common/zstd_internal.h266
-rw-r--r--Utilities/cmzstd/lib/compress/fse_compress.c721
-rw-r--r--Utilities/cmzstd/lib/compress/hist.c203
-rw-r--r--Utilities/cmzstd/lib/compress/hist.h95
-rw-r--r--Utilities/cmzstd/lib/compress/huf_compress.c798
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress.c4290
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_internal.h860
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_double_fast.c499
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_double_fast.h38
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_fast.c391
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_fast.h37
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_lazy.c1106
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_lazy.h67
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_ldm.c597
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_ldm.h105
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_opt.c1217
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_opt.h56
-rw-r--r--Utilities/cmzstd/lib/compress/zstdmt_compress.c2107
-rw-r--r--Utilities/cmzstd/lib/compress/zstdmt_compress.h174
-rw-r--r--Utilities/cmzstd/lib/decompress/huf_decompress.c1232
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_ddict.c240
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_ddict.h44
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress.c1672
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_block.c1307
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_block.h59
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h168
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff.h213
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_common.c26
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_compress.c147
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_decompress.c75
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/cover.c1081
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/cover.h83
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/divsufsort.c1913
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/divsufsort.h67
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/fastcover.c728
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/zdict.c1111
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/zdict.h267
-rw-r--r--Utilities/cmzstd/lib/zstd.h1766
-rwxr-xr-xbootstrap19
1870 files changed, 77574 insertions, 30937 deletions
diff --git a/.clang-tidy b/.clang-tidy
index 520b1a9e3..bfcb67ca7 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -11,7 +11,6 @@ misc-*,\
-misc-static-assert,\
modernize-*,\
-modernize-deprecated-headers,\
--modernize-raw-string-literal,\
-modernize-return-braced-init-list,\
-modernize-use-auto,\
-modernize-use-noexcept,\
@@ -19,7 +18,6 @@ modernize-*,\
-modernize-use-using,\
performance-*,\
-performance-inefficient-string-concatenation,\
--performance-inefficient-vector-operation,\
readability-*,\
-readability-function-size,\
-readability-identifier-naming,\
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake
index 5d67b0b85..638b1c442 100644
--- a/Auxiliary/bash-completion/cmake
+++ b/Auxiliary/bash-completion/cmake
@@ -96,7 +96,7 @@ _cmake()
_filedir
return
;;
- --build|--open)
+ --build|--install|--open)
_filedir -d
return
;;
@@ -116,6 +116,9 @@ _cmake()
2>/dev/null )' -- "$quoted" ) )
return
;;
+ --loglevel)
+ COMPREPLY=( $(compgen -W 'error warning notice status verbose debug trace' -- $cur ) )
+ ;;
--help-command)
COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null|
grep -v "^cmake version " )' -- "$cur" ) )
diff --git a/Auxiliary/cmake.m4 b/Auxiliary/cmake.m4
index 7beff41a8..a40c0ae97 100644
--- a/Auxiliary/cmake.m4
+++ b/Auxiliary/cmake.m4
@@ -13,7 +13,7 @@ fi
# $2: language (e.g. C/CXX/Fortran)
# $3: The compiler ID, defaults to GNU.
# Possible values are: GNU, Intel, Clang, SunPro, HP, XL, VisualAge, PGI,
-# PathScale, Cray, SCO, MIPSpro, MSVC
+# PathScale, Cray, SCO, MSVC
# $4: optional extra arguments to cmake, e.g. "-DCMAKE_SIZEOF_VOID_P=8"
# $5: optional path to cmake binary
AC_DEFUN([CMAKE_FIND_PACKAGE], [
diff --git a/Auxiliary/vim/cmake.vim.in b/Auxiliary/vim/cmake.vim.in
index 77ad3d884..3471b5455 100644
--- a/Auxiliary/vim/cmake.vim.in
+++ b/Auxiliary/vim/cmake.vim.in
@@ -31,11 +31,11 @@ syn region cmakeGeneratorExpression start="$<" end=">" contained oneline contain
syn region cmakeString start='"' end='"' contained contains=cmakeTodo,cmakeVariableValue,cmakeEscaped
-syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo
+syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo,cmakeVariableValue
syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
-syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
syn case match
diff --git a/Auxiliary/vim/extract-upper-case.pl b/Auxiliary/vim/extract-upper-case.pl
index bd62aded9..204b49662 100755
--- a/Auxiliary/vim/extract-upper-case.pl
+++ b/Auxiliary/vim/extract-upper-case.pl
@@ -13,6 +13,9 @@ my @properties;
my @modules;
my %keywords; # command => keyword-list
+# find cmake/Modules/ | sed -rn 's/.*CMakeDetermine(.+)Compiler.cmake/\1/p' | sort
+my @languages = qw(ASM ASM_MASM ASM_NASM C CSharp CUDA CXX Fortran Java RC Swift);
+
# unwanted upper-cases
my %unwanted = map { $_ => 1 } qw(VS CXX IDE NOTFOUND NO_ DFOO DBAR NEW);
# cannot remove ALL - exists for add_custom_command
@@ -30,8 +33,21 @@ push @modules, "ExternalProject";
# variables
open(CMAKE, "$cmake --help-variable-list|") or die "could not run cmake";
while (<CMAKE>) {
- next if /\</; # skip if containing < or >
chomp;
+
+ if (/<(.*?)>/) {
+ if ($1 eq 'LANG') {
+ foreach my $lang (@languages) {
+ (my $V = $_) =~ s/<.*>/$lang/;
+ push @variables, $V;
+ }
+
+ next
+ } else {
+ next; # skip if containing < or >
+ }
+ }
+
push @variables, $_;
}
close(CMAKE);
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 7e029de4e..cd8385b67 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -1,13 +1,13 @@
" Vim syntax file
" Program: CMake - Cross-Platform Makefile Generator
-" Version: cmake version 3.13.20181010-ga3598
+" Version: cmake version 3.14.20190529-g067a4f
" 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: 2018 Oct 18
+" Last Change: 2019 May 29
"
" Licence: The CMake license applies to this file. See
" https://cmake.org/licensing
@@ -31,16 +31,17 @@ syn region cmakeGeneratorExpression start="$<" end=">" contained oneline contain
syn region cmakeString start='"' end='"' contained contains=cmakeTodo,cmakeVariableValue,cmakeEscaped
-syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo
+syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo,cmakeVariableValue
syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
-syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
syn case match
syn keyword cmakeProperty contained
\ ABSTRACT
+ \ ADDITIONAL_CLEAN_FILES
\ ADDITIONAL_MAKE_CLEAN_FILES
\ ADVANCED
\ ALIASED_TARGET
@@ -67,6 +68,7 @@ syn keyword cmakeProperty contained
\ ATTACHED_FILES
\ ATTACHED_FILES_ON_FAIL
\ AUTOGEN_BUILD_DIR
+ \ AUTOGEN_ORIGIN_DEPENDS
\ AUTOGEN_PARALLEL
\ AUTOGEN_SOURCE_GROUP
\ AUTOGEN_TARGETS_FOLDER
@@ -74,19 +76,23 @@ syn keyword cmakeProperty contained
\ AUTOMOC
\ AUTOMOC_COMPILER_PREDEFINES
\ AUTOMOC_DEPEND_FILTERS
+ \ AUTOMOC_EXECUTABLE
\ AUTOMOC_MACRO_NAMES
\ AUTOMOC_MOC_OPTIONS
\ AUTOMOC_SOURCE_GROUP
\ AUTOMOC_TARGETS_FOLDER
\ AUTORCC
+ \ AUTORCC_EXECUTABLE
\ AUTORCC_OPTIONS
\ AUTORCC_SOURCE_GROUP
\ AUTOUIC
+ \ AUTOUIC_EXECUTABLE
\ AUTOUIC_OPTIONS
\ AUTOUIC_SEARCH_PATHS
\ BINARY_DIR
\ BUILDSYSTEM_TARGETS
\ BUILD_RPATH
+ \ BUILD_RPATH_USE_ORIGIN
\ BUILD_WITH_INSTALL_NAME_DIR
\ BUILD_WITH_INSTALL_RPATH
\ BUNDLE
@@ -96,6 +102,7 @@ syn keyword cmakeProperty contained
\ CMAKE_CONFIGURE_DEPENDS
\ CMAKE_CXX_KNOWN_FEATURES
\ CMAKE_C_KNOWN_FEATURES
+ \ CMAKE_ROLE
\ COMMON_LANGUAGE_RUNTIME
\ COMPATIBLE_INTERFACE_BOOL
\ COMPATIBLE_INTERFACE_NUMBER_MAX
@@ -165,6 +172,8 @@ syn keyword cmakeProperty contained
\ GENERATED
\ GENERATOR_FILE_NAME
\ GENERATOR_IS_MULTI_CONFIG
+ \ GHS_INTEGRITY_APP
+ \ GHS_NO_SOURCE_GROUP_FILE
\ GLOBAL_DEPENDS_DEBUG_MODE
\ GLOBAL_DEPENDS_NO_CYCLES
\ GNUtoMS
@@ -239,6 +248,7 @@ syn keyword cmakeProperty contained
\ MANUALLY_ADDED_DEPENDENCIES
\ MEASUREMENT
\ MODIFIED
+ \ MSVC_RUNTIME_LIBRARY
\ NAME
\ NO_SONAME
\ NO_SYSTEM_FROM_IMPORTED
@@ -288,6 +298,10 @@ syn keyword cmakeProperty contained
\ SUBDIRECTORIES
\ SUFFIX
\ SYMBOLIC
+ \ Swift_DEPENDENCIES_FILE
+ \ Swift_DIAGNOSTICS_FILE
+ \ Swift_MODULE_DIRECTORY
+ \ Swift_MODULE_NAME
\ TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
\ TARGET_MESSAGES
\ TARGET_SUPPORTS_SHARED_LIBS
@@ -320,8 +334,11 @@ syn keyword cmakeProperty contained
\ VS_INCLUDE_IN_VSIX
\ VS_IOT_EXTENSIONS_VERSION
\ VS_IOT_STARTUP_TASK
+ \ VS_JUST_MY_CODE_DEBUGGING
\ VS_KEYWORD
\ VS_MOBILE_EXTENSIONS_VERSION
+ \ VS_NO_SOLUTION_DEPLOY
+ \ VS_PROJECT_IMPORT
\ VS_RESOURCE_GENERATOR
\ VS_SCC_AUXPATH
\ VS_SCC_LOCALPATH
@@ -353,11 +370,13 @@ syn keyword cmakeProperty contained
\ XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
\ XCODE_EXPLICIT_FILE_TYPE
\ XCODE_FILE_ATTRIBUTES
+ \ XCODE_GENERATE_SCHEME
\ XCODE_LAST_KNOWN_FILE_TYPE
\ XCODE_PRODUCT_TYPE
\ XCODE_SCHEME_ADDRESS_SANITIZER
\ XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
\ XCODE_SCHEME_ARGUMENTS
+ \ XCODE_SCHEME_DEBUG_AS_ROOT
\ XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
\ XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
\ XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
@@ -412,6 +431,184 @@ syn keyword cmakeVariable contained
\ CMAKE_ARCHIVE_OUTPUT_DIRECTORY
\ CMAKE_ARGC
\ CMAKE_ARGV0
+ \ CMAKE_ASM
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_CLANG_TIDY
+ \ CMAKE_ASM_COMPILER
+ \ CMAKE_ASM_COMPILER_ABI
+ \ CMAKE_ASM_COMPILER_AR
+ \ CMAKE_ASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_COMPILER_ID
+ \ CMAKE_ASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_COMPILER_LOADED
+ \ CMAKE_ASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_COMPILER_RANLIB
+ \ CMAKE_ASM_COMPILER_TARGET
+ \ CMAKE_ASM_COMPILER_VERSION
+ \ CMAKE_ASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_COMPILE_OBJECT
+ \ CMAKE_ASM_CPPCHECK
+ \ CMAKE_ASM_CPPLINT
+ \ CMAKE_ASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_FLAGS
+ \ CMAKE_ASM_FLAGS_DEBUG
+ \ CMAKE_ASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_FLAGS_INIT
+ \ CMAKE_ASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_FLAGS_RELEASE
+ \ CMAKE_ASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_INIT
+ \ CMAKE_ASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_MASM
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_MASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_MASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_MASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_MASM_CLANG_TIDY
+ \ CMAKE_ASM_MASM_COMPILER
+ \ CMAKE_ASM_MASM_COMPILER_ABI
+ \ CMAKE_ASM_MASM_COMPILER_AR
+ \ CMAKE_ASM_MASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_MASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_MASM_COMPILER_ID
+ \ CMAKE_ASM_MASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_MASM_COMPILER_LOADED
+ \ CMAKE_ASM_MASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_MASM_COMPILER_RANLIB
+ \ CMAKE_ASM_MASM_COMPILER_TARGET
+ \ CMAKE_ASM_MASM_COMPILER_VERSION
+ \ CMAKE_ASM_MASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_MASM_COMPILE_OBJECT
+ \ CMAKE_ASM_MASM_CPPCHECK
+ \ CMAKE_ASM_MASM_CPPLINT
+ \ CMAKE_ASM_MASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_MASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_MASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_MASM_FLAGS
+ \ CMAKE_ASM_MASM_FLAGS_DEBUG
+ \ CMAKE_ASM_MASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_MASM_FLAGS_INIT
+ \ CMAKE_ASM_MASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_MASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_MASM_FLAGS_RELEASE
+ \ CMAKE_ASM_MASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_MASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_MASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_MASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_MASM_INIT
+ \ CMAKE_ASM_MASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_MASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_MASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_MASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_MASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_MASM_PLATFORM_ID
+ \ CMAKE_ASM_MASM_SIMULATE_ID
+ \ CMAKE_ASM_MASM_SIMULATE_VERSION
+ \ CMAKE_ASM_MASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_MASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_MASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_MASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_MASM_VISIBILITY_PRESET
+ \ CMAKE_ASM_NASM
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_NASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_NASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_NASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_NASM_CLANG_TIDY
+ \ CMAKE_ASM_NASM_COMPILER
+ \ CMAKE_ASM_NASM_COMPILER_ABI
+ \ CMAKE_ASM_NASM_COMPILER_AR
+ \ CMAKE_ASM_NASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_NASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_NASM_COMPILER_ID
+ \ CMAKE_ASM_NASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_NASM_COMPILER_LOADED
+ \ CMAKE_ASM_NASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_NASM_COMPILER_RANLIB
+ \ CMAKE_ASM_NASM_COMPILER_TARGET
+ \ CMAKE_ASM_NASM_COMPILER_VERSION
+ \ CMAKE_ASM_NASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_NASM_COMPILE_OBJECT
+ \ CMAKE_ASM_NASM_CPPCHECK
+ \ CMAKE_ASM_NASM_CPPLINT
+ \ CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_NASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_NASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_NASM_FLAGS
+ \ CMAKE_ASM_NASM_FLAGS_DEBUG
+ \ CMAKE_ASM_NASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_NASM_FLAGS_INIT
+ \ CMAKE_ASM_NASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_NASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_NASM_FLAGS_RELEASE
+ \ CMAKE_ASM_NASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_NASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_NASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_NASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_NASM_INIT
+ \ CMAKE_ASM_NASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_NASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_NASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_NASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_NASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_NASM_PLATFORM_ID
+ \ CMAKE_ASM_NASM_SIMULATE_ID
+ \ CMAKE_ASM_NASM_SIMULATE_VERSION
+ \ CMAKE_ASM_NASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_NASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_NASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_NASM_VISIBILITY_PRESET
+ \ CMAKE_ASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_PLATFORM_ID
+ \ CMAKE_ASM_SIMULATE_ID
+ \ CMAKE_ASM_SIMULATE_VERSION
+ \ CMAKE_ASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_VISIBILITY_PRESET
+ \ CMAKE_AUTOGEN_ORIGIN_DEPENDS
\ CMAKE_AUTOGEN_PARALLEL
\ CMAKE_AUTOGEN_VERBOSE
\ CMAKE_AUTOMOC
@@ -428,10 +625,12 @@ syn keyword cmakeVariable contained
\ CMAKE_BACKWARDS_COMPATIBILITY
\ CMAKE_BINARY_DIR
\ CMAKE_BUILD_RPATH
+ \ CMAKE_BUILD_RPATH_USE_ORIGIN
\ CMAKE_BUILD_TOOL
\ CMAKE_BUILD_TYPE
\ CMAKE_BUILD_WITH_INSTALL_NAME_DIR
\ CMAKE_BUILD_WITH_INSTALL_RPATH
+ \ CMAKE_C
\ CMAKE_CACHEFILE_DIR
\ CMAKE_CACHE_MAJOR_VERSION
\ CMAKE_CACHE_MINOR_VERSION
@@ -452,26 +651,261 @@ syn keyword cmakeVariable contained
\ CMAKE_CPACK_COMMAND
\ CMAKE_CROSSCOMPILING
\ CMAKE_CROSSCOMPILING_EMULATOR
+ \ CMAKE_CSharp
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CSharp_ARCHIVE_APPEND
+ \ CMAKE_CSharp_ARCHIVE_CREATE
+ \ CMAKE_CSharp_ARCHIVE_FINISH
+ \ CMAKE_CSharp_CLANG_TIDY
+ \ CMAKE_CSharp_COMPILER
+ \ CMAKE_CSharp_COMPILER_ABI
+ \ CMAKE_CSharp_COMPILER_AR
+ \ CMAKE_CSharp_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CSharp_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CSharp_COMPILER_ID
+ \ CMAKE_CSharp_COMPILER_LAUNCHER
+ \ CMAKE_CSharp_COMPILER_LOADED
+ \ CMAKE_CSharp_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CSharp_COMPILER_RANLIB
+ \ CMAKE_CSharp_COMPILER_TARGET
+ \ CMAKE_CSharp_COMPILER_VERSION
+ \ CMAKE_CSharp_COMPILER_VERSION_INTERNAL
+ \ CMAKE_CSharp_COMPILE_OBJECT
+ \ CMAKE_CSharp_CPPCHECK
+ \ CMAKE_CSharp_CPPLINT
+ \ CMAKE_CSharp_CREATE_SHARED_LIBRARY
+ \ CMAKE_CSharp_CREATE_SHARED_MODULE
+ \ CMAKE_CSharp_CREATE_STATIC_LIBRARY
+ \ CMAKE_CSharp_FLAGS
+ \ CMAKE_CSharp_FLAGS_DEBUG
+ \ CMAKE_CSharp_FLAGS_DEBUG_INIT
+ \ CMAKE_CSharp_FLAGS_INIT
+ \ CMAKE_CSharp_FLAGS_MINSIZEREL
+ \ CMAKE_CSharp_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CSharp_FLAGS_RELEASE
+ \ CMAKE_CSharp_FLAGS_RELEASE_INIT
+ \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_CSharp_IGNORE_EXTENSIONS
+ \ CMAKE_CSharp_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CSharp_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CSharp_INIT
+ \ CMAKE_CSharp_LIBRARY_ARCHITECTURE
+ \ CMAKE_CSharp_LINKER_PREFERENCE
+ \ CMAKE_CSharp_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CSharp_LINKER_WRAPPER_FLAG
+ \ CMAKE_CSharp_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CSharp_LINK_EXECUTABLE
+ \ CMAKE_CSharp_OUTPUT_EXTENSION
+ \ CMAKE_CSharp_PLATFORM_ID
+ \ CMAKE_CSharp_SIMULATE_ID
+ \ CMAKE_CSharp_SIMULATE_VERSION
+ \ CMAKE_CSharp_SIZEOF_DATA_PTR
+ \ CMAKE_CSharp_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_CSharp_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CSharp_STANDARD_LIBRARIES
+ \ CMAKE_CSharp_VISIBILITY_PRESET
\ CMAKE_CTEST_COMMAND
+ \ CMAKE_CUDA
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CUDA_ARCHIVE_APPEND
+ \ CMAKE_CUDA_ARCHIVE_CREATE
+ \ CMAKE_CUDA_ARCHIVE_FINISH
+ \ CMAKE_CUDA_CLANG_TIDY
+ \ CMAKE_CUDA_COMPILER
+ \ CMAKE_CUDA_COMPILER_ABI
+ \ CMAKE_CUDA_COMPILER_AR
+ \ CMAKE_CUDA_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CUDA_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CUDA_COMPILER_ID
+ \ CMAKE_CUDA_COMPILER_LAUNCHER
+ \ CMAKE_CUDA_COMPILER_LOADED
+ \ CMAKE_CUDA_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CUDA_COMPILER_RANLIB
+ \ CMAKE_CUDA_COMPILER_TARGET
+ \ CMAKE_CUDA_COMPILER_VERSION
+ \ CMAKE_CUDA_COMPILER_VERSION_INTERNAL
+ \ CMAKE_CUDA_COMPILE_OBJECT
+ \ CMAKE_CUDA_CPPCHECK
+ \ CMAKE_CUDA_CPPLINT
+ \ CMAKE_CUDA_CREATE_SHARED_LIBRARY
+ \ CMAKE_CUDA_CREATE_SHARED_MODULE
+ \ CMAKE_CUDA_CREATE_STATIC_LIBRARY
\ CMAKE_CUDA_EXTENSIONS
+ \ CMAKE_CUDA_FLAGS
+ \ CMAKE_CUDA_FLAGS_DEBUG
+ \ CMAKE_CUDA_FLAGS_DEBUG_INIT
+ \ CMAKE_CUDA_FLAGS_INIT
+ \ CMAKE_CUDA_FLAGS_MINSIZEREL
+ \ CMAKE_CUDA_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CUDA_FLAGS_RELEASE
+ \ CMAKE_CUDA_FLAGS_RELEASE_INIT
+ \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT
\ CMAKE_CUDA_HOST_COMPILER
+ \ CMAKE_CUDA_IGNORE_EXTENSIONS
+ \ CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CUDA_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CUDA_INIT
+ \ CMAKE_CUDA_LIBRARY_ARCHITECTURE
+ \ CMAKE_CUDA_LINKER_PREFERENCE
+ \ CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CUDA_LINKER_WRAPPER_FLAG
+ \ CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CUDA_LINK_EXECUTABLE
+ \ CMAKE_CUDA_OUTPUT_EXTENSION
+ \ CMAKE_CUDA_PLATFORM_ID
\ CMAKE_CUDA_SEPARABLE_COMPILATION
+ \ CMAKE_CUDA_SIMULATE_ID
+ \ CMAKE_CUDA_SIMULATE_VERSION
+ \ CMAKE_CUDA_SIZEOF_DATA_PTR
+ \ CMAKE_CUDA_SOURCE_FILE_EXTENSIONS
\ CMAKE_CUDA_STANDARD
+ \ CMAKE_CUDA_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_STANDARD_LIBRARIES
\ CMAKE_CUDA_STANDARD_REQUIRED
\ CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_VISIBILITY_PRESET
\ CMAKE_CURRENT_BINARY_DIR
\ CMAKE_CURRENT_LIST_DIR
\ CMAKE_CURRENT_LIST_FILE
\ CMAKE_CURRENT_LIST_LINE
\ CMAKE_CURRENT_SOURCE_DIR
+ \ CMAKE_CXX
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CXX_ARCHIVE_APPEND
+ \ CMAKE_CXX_ARCHIVE_CREATE
+ \ CMAKE_CXX_ARCHIVE_FINISH
+ \ CMAKE_CXX_CLANG_TIDY
+ \ CMAKE_CXX_COMPILER
+ \ CMAKE_CXX_COMPILER_ABI
+ \ CMAKE_CXX_COMPILER_AR
+ \ CMAKE_CXX_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CXX_COMPILER_ID
+ \ CMAKE_CXX_COMPILER_LAUNCHER
+ \ CMAKE_CXX_COMPILER_LOADED
+ \ CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CXX_COMPILER_RANLIB
+ \ CMAKE_CXX_COMPILER_TARGET
+ \ CMAKE_CXX_COMPILER_VERSION
+ \ CMAKE_CXX_COMPILER_VERSION_INTERNAL
\ CMAKE_CXX_COMPILE_FEATURES
+ \ CMAKE_CXX_COMPILE_OBJECT
+ \ CMAKE_CXX_CPPCHECK
+ \ CMAKE_CXX_CPPLINT
+ \ CMAKE_CXX_CREATE_SHARED_LIBRARY
+ \ CMAKE_CXX_CREATE_SHARED_MODULE
+ \ CMAKE_CXX_CREATE_STATIC_LIBRARY
\ CMAKE_CXX_EXTENSIONS
+ \ CMAKE_CXX_FLAGS
+ \ CMAKE_CXX_FLAGS_DEBUG
+ \ CMAKE_CXX_FLAGS_DEBUG_INIT
+ \ CMAKE_CXX_FLAGS_INIT
+ \ CMAKE_CXX_FLAGS_MINSIZEREL
+ \ CMAKE_CXX_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CXX_FLAGS_RELEASE
+ \ CMAKE_CXX_FLAGS_RELEASE_INIT
+ \ CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_CXX_IGNORE_EXTENSIONS
+ \ CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CXX_INIT
+ \ CMAKE_CXX_LIBRARY_ARCHITECTURE
+ \ CMAKE_CXX_LINKER_PREFERENCE
+ \ CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CXX_LINKER_WRAPPER_FLAG
+ \ CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CXX_LINK_EXECUTABLE
+ \ CMAKE_CXX_OUTPUT_EXTENSION
+ \ CMAKE_CXX_PLATFORM_ID
+ \ CMAKE_CXX_SIMULATE_ID
+ \ CMAKE_CXX_SIMULATE_VERSION
+ \ CMAKE_CXX_SIZEOF_DATA_PTR
+ \ CMAKE_CXX_SOURCE_FILE_EXTENSIONS
\ CMAKE_CXX_STANDARD
+ \ CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CXX_STANDARD_LIBRARIES
\ CMAKE_CXX_STANDARD_REQUIRED
+ \ CMAKE_CXX_VISIBILITY_PRESET
+ \ CMAKE_C_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_C_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_C_ARCHIVE_APPEND
+ \ CMAKE_C_ARCHIVE_CREATE
+ \ CMAKE_C_ARCHIVE_FINISH
+ \ CMAKE_C_CLANG_TIDY
+ \ CMAKE_C_COMPILER
+ \ CMAKE_C_COMPILER_ABI
+ \ CMAKE_C_COMPILER_AR
+ \ CMAKE_C_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_C_COMPILER_ID
+ \ CMAKE_C_COMPILER_LAUNCHER
+ \ CMAKE_C_COMPILER_LOADED
+ \ CMAKE_C_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_C_COMPILER_RANLIB
+ \ CMAKE_C_COMPILER_TARGET
+ \ CMAKE_C_COMPILER_VERSION
+ \ CMAKE_C_COMPILER_VERSION_INTERNAL
\ CMAKE_C_COMPILE_FEATURES
+ \ CMAKE_C_COMPILE_OBJECT
+ \ CMAKE_C_CPPCHECK
+ \ CMAKE_C_CPPLINT
+ \ CMAKE_C_CREATE_SHARED_LIBRARY
+ \ CMAKE_C_CREATE_SHARED_MODULE
+ \ CMAKE_C_CREATE_STATIC_LIBRARY
\ CMAKE_C_EXTENSIONS
+ \ CMAKE_C_FLAGS
+ \ CMAKE_C_FLAGS_DEBUG
+ \ CMAKE_C_FLAGS_DEBUG_INIT
+ \ CMAKE_C_FLAGS_INIT
+ \ CMAKE_C_FLAGS_MINSIZEREL
+ \ CMAKE_C_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_C_FLAGS_RELEASE
+ \ CMAKE_C_FLAGS_RELEASE_INIT
+ \ CMAKE_C_FLAGS_RELWITHDEBINFO
+ \ CMAKE_C_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_C_IGNORE_EXTENSIONS
+ \ CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_C_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_C_INIT
+ \ CMAKE_C_LIBRARY_ARCHITECTURE
+ \ CMAKE_C_LINKER_PREFERENCE
+ \ CMAKE_C_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_C_LINKER_WRAPPER_FLAG
+ \ CMAKE_C_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_C_LINK_EXECUTABLE
+ \ CMAKE_C_OUTPUT_EXTENSION
+ \ CMAKE_C_PLATFORM_ID
+ \ CMAKE_C_SIMULATE_ID
+ \ CMAKE_C_SIMULATE_VERSION
+ \ CMAKE_C_SIZEOF_DATA_PTR
+ \ CMAKE_C_SOURCE_FILE_EXTENSIONS
\ CMAKE_C_STANDARD
+ \ CMAKE_C_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_C_STANDARD_LIBRARIES
\ CMAKE_C_STANDARD_REQUIRED
+ \ CMAKE_C_VISIBILITY_PRESET
\ CMAKE_DEBUG_POSTFIX
\ CMAKE_DEBUG_TARGET_PROPERTIES
\ CMAKE_DEPENDS_IN_PROJECT_ONLY
@@ -487,10 +921,12 @@ syn keyword cmakeVariable contained
\ CMAKE_ERROR_DEPRECATED
\ CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
\ CMAKE_EXECUTABLE_SUFFIX
+ \ CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
\ CMAKE_EXE_LINKER_FLAGS
\ CMAKE_EXE_LINKER_FLAGS_INIT
\ CMAKE_EXPORT_COMPILE_COMMANDS
\ CMAKE_EXPORT_NO_PACKAGE_REGISTRY
+ \ CMAKE_EXPORT_PACKAGE_REGISTRY
\ CMAKE_EXTRA_GENERATOR
\ CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
\ CMAKE_FIND_APPBUNDLE
@@ -502,6 +938,8 @@ syn keyword cmakeVariable contained
\ CMAKE_FIND_PACKAGE_NAME
\ CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
\ CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+ \ CMAKE_FIND_PACKAGE_PREFER_CONFIG
+ \ CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS
\ CMAKE_FIND_PACKAGE_SORT_DIRECTION
\ CMAKE_FIND_PACKAGE_SORT_ORDER
\ CMAKE_FIND_PACKAGE_WARN_NO_MODULE
@@ -511,16 +949,81 @@ syn keyword cmakeVariable contained
\ CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
\ CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
\ CMAKE_FOLDER
+ \ CMAKE_FRAMEWORK
\ CMAKE_FRAMEWORK_PATH
+ \ CMAKE_Fortran
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Fortran_ARCHIVE_APPEND
+ \ CMAKE_Fortran_ARCHIVE_CREATE
+ \ CMAKE_Fortran_ARCHIVE_FINISH
+ \ CMAKE_Fortran_CLANG_TIDY
+ \ CMAKE_Fortran_COMPILER
+ \ CMAKE_Fortran_COMPILER_ABI
+ \ CMAKE_Fortran_COMPILER_AR
+ \ CMAKE_Fortran_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Fortran_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Fortran_COMPILER_ID
+ \ CMAKE_Fortran_COMPILER_LAUNCHER
+ \ CMAKE_Fortran_COMPILER_LOADED
+ \ CMAKE_Fortran_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Fortran_COMPILER_RANLIB
+ \ CMAKE_Fortran_COMPILER_TARGET
+ \ CMAKE_Fortran_COMPILER_VERSION
+ \ CMAKE_Fortran_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Fortran_COMPILE_OBJECT
+ \ CMAKE_Fortran_CPPCHECK
+ \ CMAKE_Fortran_CPPLINT
+ \ CMAKE_Fortran_CREATE_SHARED_LIBRARY
+ \ CMAKE_Fortran_CREATE_SHARED_MODULE
+ \ CMAKE_Fortran_CREATE_STATIC_LIBRARY
+ \ CMAKE_Fortran_FLAGS
+ \ CMAKE_Fortran_FLAGS_DEBUG
+ \ CMAKE_Fortran_FLAGS_DEBUG_INIT
+ \ CMAKE_Fortran_FLAGS_INIT
+ \ CMAKE_Fortran_FLAGS_MINSIZEREL
+ \ CMAKE_Fortran_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Fortran_FLAGS_RELEASE
+ \ CMAKE_Fortran_FLAGS_RELEASE_INIT
+ \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT
\ CMAKE_Fortran_FORMAT
+ \ CMAKE_Fortran_IGNORE_EXTENSIONS
+ \ CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Fortran_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Fortran_INIT
+ \ CMAKE_Fortran_LIBRARY_ARCHITECTURE
+ \ CMAKE_Fortran_LINKER_PREFERENCE
+ \ CMAKE_Fortran_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Fortran_LINKER_WRAPPER_FLAG
+ \ CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Fortran_LINK_EXECUTABLE
\ CMAKE_Fortran_MODDIR_DEFAULT
\ CMAKE_Fortran_MODDIR_FLAG
\ CMAKE_Fortran_MODOUT_FLAG
\ CMAKE_Fortran_MODULE_DIRECTORY
+ \ CMAKE_Fortran_OUTPUT_EXTENSION
+ \ CMAKE_Fortran_PLATFORM_ID
+ \ CMAKE_Fortran_SIMULATE_ID
+ \ CMAKE_Fortran_SIMULATE_VERSION
+ \ CMAKE_Fortran_SIZEOF_DATA_PTR
+ \ CMAKE_Fortran_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Fortran_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Fortran_STANDARD_LIBRARIES
+ \ CMAKE_Fortran_VISIBILITY_PRESET
\ CMAKE_GENERATOR
\ CMAKE_GENERATOR_INSTANCE
\ CMAKE_GENERATOR_PLATFORM
\ CMAKE_GENERATOR_TOOLSET
+ \ CMAKE_GHS_NO_SOURCE_GROUP_FILE
+ \ CMAKE_GLOBAL_AUTOGEN_TARGET
+ \ CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+ \ CMAKE_GLOBAL_AUTORCC_TARGET
+ \ CMAKE_GLOBAL_AUTORCC_TARGET_NAME
\ CMAKE_GNUtoMS
\ CMAKE_HOME_DIRECTORY
\ CMAKE_HOST_APPLE
@@ -553,6 +1056,65 @@ syn keyword cmakeVariable contained
\ CMAKE_JOB_POOLS
\ CMAKE_JOB_POOL_COMPILE
\ CMAKE_JOB_POOL_LINK
+ \ CMAKE_Java
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Java_ARCHIVE_APPEND
+ \ CMAKE_Java_ARCHIVE_CREATE
+ \ CMAKE_Java_ARCHIVE_FINISH
+ \ CMAKE_Java_CLANG_TIDY
+ \ CMAKE_Java_COMPILER
+ \ CMAKE_Java_COMPILER_ABI
+ \ CMAKE_Java_COMPILER_AR
+ \ CMAKE_Java_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Java_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Java_COMPILER_ID
+ \ CMAKE_Java_COMPILER_LAUNCHER
+ \ CMAKE_Java_COMPILER_LOADED
+ \ CMAKE_Java_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Java_COMPILER_RANLIB
+ \ CMAKE_Java_COMPILER_TARGET
+ \ CMAKE_Java_COMPILER_VERSION
+ \ CMAKE_Java_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Java_COMPILE_OBJECT
+ \ CMAKE_Java_CPPCHECK
+ \ CMAKE_Java_CPPLINT
+ \ CMAKE_Java_CREATE_SHARED_LIBRARY
+ \ CMAKE_Java_CREATE_SHARED_MODULE
+ \ CMAKE_Java_CREATE_STATIC_LIBRARY
+ \ CMAKE_Java_FLAGS
+ \ CMAKE_Java_FLAGS_DEBUG
+ \ CMAKE_Java_FLAGS_DEBUG_INIT
+ \ CMAKE_Java_FLAGS_INIT
+ \ CMAKE_Java_FLAGS_MINSIZEREL
+ \ CMAKE_Java_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Java_FLAGS_RELEASE
+ \ CMAKE_Java_FLAGS_RELEASE_INIT
+ \ CMAKE_Java_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Java_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_Java_IGNORE_EXTENSIONS
+ \ CMAKE_Java_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Java_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Java_INIT
+ \ CMAKE_Java_LIBRARY_ARCHITECTURE
+ \ CMAKE_Java_LINKER_PREFERENCE
+ \ CMAKE_Java_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Java_LINKER_WRAPPER_FLAG
+ \ CMAKE_Java_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Java_LINK_EXECUTABLE
+ \ CMAKE_Java_OUTPUT_EXTENSION
+ \ CMAKE_Java_PLATFORM_ID
+ \ CMAKE_Java_SIMULATE_ID
+ \ CMAKE_Java_SIMULATE_VERSION
+ \ CMAKE_Java_SIZEOF_DATA_PTR
+ \ CMAKE_Java_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Java_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Java_STANDARD_LIBRARIES
+ \ CMAKE_Java_VISIBILITY_PRESET
\ CMAKE_LIBRARY_ARCHITECTURE
\ CMAKE_LIBRARY_ARCHITECTURE_REGEX
\ CMAKE_LIBRARY_OUTPUT_DIRECTORY
@@ -573,6 +1135,7 @@ syn keyword cmakeVariable contained
\ CMAKE_MAJOR_VERSION
\ CMAKE_MAKE_PROGRAM
\ CMAKE_MATCH_COUNT
+ \ CMAKE_MAXIMUM_RECURSION_DEPTH
\ CMAKE_MFC_FLAG
\ CMAKE_MINIMUM_REQUIRED_VERSION
\ CMAKE_MINOR_VERSION
@@ -580,6 +1143,7 @@ syn keyword cmakeVariable contained
\ CMAKE_MODULE_LINKER_FLAGS_INIT
\ CMAKE_MODULE_PATH
\ CMAKE_MSVCIDE_RUN_PATH
+ \ CMAKE_MSVC_RUNTIME_LIBRARY
\ CMAKE_NETRC
\ CMAKE_NETRC_FILE
\ CMAKE_NINJA_OUTPUT_PATH_PREFIX
@@ -598,6 +1162,8 @@ syn keyword cmakeVariable contained
\ CMAKE_PROGRAM_PATH
\ CMAKE_PROJECT_DESCRIPTION
\ CMAKE_PROJECT_HOMEPAGE_URL
+ \ CMAKE_PROJECT_INCLUDE
+ \ CMAKE_PROJECT_INCLUDE_BEFORE
\ CMAKE_PROJECT_NAME
\ CMAKE_PROJECT_VERSION
\ CMAKE_PROJECT_VERSION_MAJOR
@@ -605,6 +1171,65 @@ syn keyword cmakeVariable contained
\ CMAKE_PROJECT_VERSION_PATCH
\ CMAKE_PROJECT_VERSION_TWEAK
\ CMAKE_RANLIB
+ \ CMAKE_RC
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_RC_ARCHIVE_APPEND
+ \ CMAKE_RC_ARCHIVE_CREATE
+ \ CMAKE_RC_ARCHIVE_FINISH
+ \ CMAKE_RC_CLANG_TIDY
+ \ CMAKE_RC_COMPILER
+ \ CMAKE_RC_COMPILER_ABI
+ \ CMAKE_RC_COMPILER_AR
+ \ CMAKE_RC_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_RC_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_RC_COMPILER_ID
+ \ CMAKE_RC_COMPILER_LAUNCHER
+ \ CMAKE_RC_COMPILER_LOADED
+ \ CMAKE_RC_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_RC_COMPILER_RANLIB
+ \ CMAKE_RC_COMPILER_TARGET
+ \ CMAKE_RC_COMPILER_VERSION
+ \ CMAKE_RC_COMPILER_VERSION_INTERNAL
+ \ CMAKE_RC_COMPILE_OBJECT
+ \ CMAKE_RC_CPPCHECK
+ \ CMAKE_RC_CPPLINT
+ \ CMAKE_RC_CREATE_SHARED_LIBRARY
+ \ CMAKE_RC_CREATE_SHARED_MODULE
+ \ CMAKE_RC_CREATE_STATIC_LIBRARY
+ \ CMAKE_RC_FLAGS
+ \ CMAKE_RC_FLAGS_DEBUG
+ \ CMAKE_RC_FLAGS_DEBUG_INIT
+ \ CMAKE_RC_FLAGS_INIT
+ \ CMAKE_RC_FLAGS_MINSIZEREL
+ \ CMAKE_RC_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_RC_FLAGS_RELEASE
+ \ CMAKE_RC_FLAGS_RELEASE_INIT
+ \ CMAKE_RC_FLAGS_RELWITHDEBINFO
+ \ CMAKE_RC_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_RC_IGNORE_EXTENSIONS
+ \ CMAKE_RC_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_RC_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_RC_INIT
+ \ CMAKE_RC_LIBRARY_ARCHITECTURE
+ \ CMAKE_RC_LINKER_PREFERENCE
+ \ CMAKE_RC_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_RC_LINKER_WRAPPER_FLAG
+ \ CMAKE_RC_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_RC_LINK_EXECUTABLE
+ \ CMAKE_RC_OUTPUT_EXTENSION
+ \ CMAKE_RC_PLATFORM_ID
+ \ CMAKE_RC_SIMULATE_ID
+ \ CMAKE_RC_SIMULATE_VERSION
+ \ CMAKE_RC_SIZEOF_DATA_PTR
+ \ CMAKE_RC_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_RC_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_RC_STANDARD_LIBRARIES
+ \ CMAKE_RC_VISIBILITY_PRESET
\ CMAKE_ROOT
\ CMAKE_RULE_MESSAGES
\ CMAKE_RUNTIME_OUTPUT_DIRECTORY
@@ -644,13 +1269,84 @@ syn keyword cmakeVariable contained
\ CMAKE_SYSTEM_PROCESSOR
\ CMAKE_SYSTEM_PROGRAM_PATH
\ CMAKE_SYSTEM_VERSION
+ \ CMAKE_Swift
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Swift_ARCHIVE_APPEND
+ \ CMAKE_Swift_ARCHIVE_CREATE
+ \ CMAKE_Swift_ARCHIVE_FINISH
+ \ CMAKE_Swift_CLANG_TIDY
+ \ CMAKE_Swift_COMPILER
+ \ CMAKE_Swift_COMPILER_ABI
+ \ CMAKE_Swift_COMPILER_AR
+ \ CMAKE_Swift_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Swift_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Swift_COMPILER_ID
+ \ CMAKE_Swift_COMPILER_LAUNCHER
+ \ CMAKE_Swift_COMPILER_LOADED
+ \ CMAKE_Swift_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Swift_COMPILER_RANLIB
+ \ CMAKE_Swift_COMPILER_TARGET
+ \ CMAKE_Swift_COMPILER_VERSION
+ \ CMAKE_Swift_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Swift_COMPILE_OBJECT
+ \ CMAKE_Swift_CPPCHECK
+ \ CMAKE_Swift_CPPLINT
+ \ CMAKE_Swift_CREATE_SHARED_LIBRARY
+ \ CMAKE_Swift_CREATE_SHARED_MODULE
+ \ CMAKE_Swift_CREATE_STATIC_LIBRARY
+ \ CMAKE_Swift_FLAGS
+ \ CMAKE_Swift_FLAGS_DEBUG
+ \ CMAKE_Swift_FLAGS_DEBUG_INIT
+ \ CMAKE_Swift_FLAGS_INIT
+ \ CMAKE_Swift_FLAGS_MINSIZEREL
+ \ CMAKE_Swift_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Swift_FLAGS_RELEASE
+ \ CMAKE_Swift_FLAGS_RELEASE_INIT
+ \ CMAKE_Swift_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_Swift_IGNORE_EXTENSIONS
+ \ CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Swift_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Swift_INIT
\ CMAKE_Swift_LANGUAGE_VERSION
+ \ CMAKE_Swift_LIBRARY_ARCHITECTURE
+ \ CMAKE_Swift_LINKER_PREFERENCE
+ \ CMAKE_Swift_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Swift_LINKER_WRAPPER_FLAG
+ \ CMAKE_Swift_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Swift_LINK_EXECUTABLE
+ \ CMAKE_Swift_MODULE_DIRECTORY
+ \ CMAKE_Swift_OUTPUT_EXTENSION
+ \ CMAKE_Swift_PLATFORM_ID
+ \ CMAKE_Swift_SIMULATE_ID
+ \ CMAKE_Swift_SIMULATE_VERSION
+ \ CMAKE_Swift_SIZEOF_DATA_PTR
+ \ CMAKE_Swift_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Swift_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Swift_STANDARD_LIBRARIES
+ \ CMAKE_Swift_VISIBILITY_PRESET
\ CMAKE_TOOLCHAIN_FILE
\ CMAKE_TRY_COMPILE_CONFIGURATION
\ CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
\ CMAKE_TRY_COMPILE_TARGET_TYPE
\ CMAKE_TWEAK_VERSION
\ CMAKE_USER_MAKE_RULES_OVERRIDE
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM_MASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM_NASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_C
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CSharp
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CUDA
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Java
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_RC
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Swift
\ CMAKE_USE_RELATIVE_PATHS
\ CMAKE_VERBOSE_MAKEFILE
\ CMAKE_VERSION
@@ -660,9 +1356,11 @@ syn keyword cmakeVariable contained
\ CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
\ CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
\ CMAKE_VS_INTEL_Fortran_PROJECT_VERSION
+ \ CMAKE_VS_JUST_MY_CODE_DEBUGGING
\ CMAKE_VS_MSBUILD_COMMAND
\ CMAKE_VS_NsightTegra_VERSION
\ CMAKE_VS_PLATFORM_NAME
+ \ CMAKE_VS_PLATFORM_NAME_DEFAULT
\ CMAKE_VS_PLATFORM_TOOLSET
\ CMAKE_VS_PLATFORM_TOOLSET_CUDA
\ CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
@@ -767,6 +1465,7 @@ syn keyword cmakeVariable contained
\ CTEST_SCP_COMMAND
\ CTEST_SITE
\ CTEST_SOURCE_DIRECTORY
+ \ CTEST_SUBMIT_URL
\ CTEST_SVN_COMMAND
\ CTEST_SVN_OPTIONS
\ CTEST_SVN_UPDATE_OPTIONS
@@ -776,11 +1475,13 @@ syn keyword cmakeVariable contained
\ CTEST_UPDATE_COMMAND
\ CTEST_UPDATE_OPTIONS
\ CTEST_UPDATE_VERSION_ONLY
+ \ CTEST_UPDATE_VERSION_OVERRIDE
\ CTEST_USE_LAUNCHERS
\ CYGWIN
\ ENV
\ EXECUTABLE_OUTPUT_PATH
\ GHS-MULTI
+ \ IOS
\ LIBRARY_OUTPUT_PATH
\ MINGW
\ MSVC
@@ -796,6 +1497,7 @@ syn keyword cmakeVariable contained
\ MSVC_IDE
\ MSVC_TOOLSET_VERSION
\ MSVC_VERSION
+ \ MSYS
\ PROJECT_BINARY_DIR
\ PROJECT_DESCRIPTION
\ PROJECT_HOMEPAGE_URL
@@ -852,6 +1554,7 @@ syn keyword cmakeKWExternalProject contained
\ EP_UPDATE_DISCONNECTED
\ EXCLUDE_FROM_ALL
\ FORCE
+ \ GHS
\ GIT_CONFIG
\ GIT_PROGRESS
\ GIT_REMOTE_NAME
@@ -870,7 +1573,6 @@ syn keyword cmakeKWExternalProject contained
\ INSTALL_DIR
\ JOB_POOLS
\ LIST_SEPARATOR
- \ LOG_
\ LOG_BUILD
\ LOG_CONFIGURE
\ LOG_DIR
@@ -882,6 +1584,7 @@ syn keyword cmakeKWExternalProject contained
\ LOG_TEST
\ LOG_UPDATE
\ MAKE_EXE
+ \ MULTI
\ NAMES
\ NETRC
\ NETRC_FILE
@@ -931,6 +1634,7 @@ syn keyword cmakeKWadd_compile_options contained
\ COMPILE_OPTIONS
\ SHELL
\ UNIX_COMMAND
+ \ WX
syn keyword cmakeKWadd_custom_command contained
\ APPEND
@@ -946,6 +1650,8 @@ syn keyword cmakeKWadd_custom_command contained
\ GENERATED
\ IMPLICIT_DEPENDS
\ INCLUDE_DIRECTORIES
+ \ JOB_POOL
+ \ JOB_POOLS
\ JOIN
\ MAIN_DEPENDENCY
\ NOT
@@ -971,6 +1677,8 @@ syn keyword cmakeKWadd_custom_target contained
\ DEPENDS
\ GENERATED
\ INCLUDE_DIRECTORIES
+ \ JOB_POOL
+ \ JOB_POOLS
\ JOIN
\ SOURCES
\ TARGET_PROPERTY
@@ -1026,6 +1734,7 @@ syn keyword cmakeKWadd_library contained
\ POST_BUILD
\ PRE_BUILD
\ PRE_LINK
+ \ PUBLIC_HEADER
\ RUNTIME_OUTPUT_DIRECTORY
\ SHARED
\ STATIC
@@ -1040,6 +1749,7 @@ syn keyword cmakeKWadd_link_options contained
\ LINKER
\ LINK_OPTIONS
\ SHELL
+ \ STATIC_LIBRARY_OPTIONS
\ UNIX_COMMAND
\ _LINKER_WRAPPER_FLAG
\ _LINKER_WRAPPER_FLAG_SEP
@@ -1053,6 +1763,7 @@ syn keyword cmakeKWadd_test contained
\ CONFIGURATIONS
\ FAIL_REGULAR_EXPRESSION
\ NAME
+ \ OFF
\ PASS_REGULAR_EXPRESSION
\ TARGET_FILE
\ WILL_FAIL
@@ -1062,9 +1773,6 @@ syn keyword cmakeKWbuild_command contained
\ CONFIGURATION
\ TARGET
-syn keyword cmakeKWbuild_name contained
- \ CMAKE_CXX_COMPILER
-
syn keyword cmakeKWcmake_host_system_information contained
\ AVAILABLE_PHYSICAL_MEMORY
\ AVAILABLE_VIRTUAL_MEMORY
@@ -1107,6 +1815,7 @@ syn keyword cmakeKWcmake_parse_arguments contained
\ MY_INSTALL_CONFIGURATIONS
\ MY_INSTALL_DESTINATION
\ MY_INSTALL_FAST
+ \ MY_INSTALL_KEYWORDS_MISSING_VALUES
\ MY_INSTALL_OPTIONAL
\ MY_INSTALL_RENAME
\ MY_INSTALL_TARGETS
@@ -1117,6 +1826,7 @@ syn keyword cmakeKWcmake_parse_arguments contained
\ TARGETS
\ TRUE
\ UNDEFINED
+ \ _KEYWORDS_MISSING_VALUES
\ _UNPARSED_ARGUMENTS
syn keyword cmakeKWcmake_policy contained
@@ -1157,7 +1867,6 @@ syn keyword cmakeKWctest_build contained
\ CTEST_BUILD_CONFIGURATION
\ CTEST_BUILD_FLAGS
\ CTEST_BUILD_TARGET
- \ CTEST_PROJECT_NAME
\ FLAGS
\ NUMBER_ERRORS
\ NUMBER_WARNINGS
@@ -1216,6 +1925,7 @@ syn keyword cmakeKWctest_start contained
syn keyword cmakeKWctest_submit contained
\ API
+ \ BUILD_ID
\ CAPTURE_CMAKE_ERROR
\ CDASH_UPLOAD
\ CDASH_UPLOAD_TYPE
@@ -1228,6 +1938,7 @@ syn keyword cmakeKWctest_submit contained
\ RETRY_COUNT
\ RETRY_DELAY
\ RETURN_VALUE
+ \ SUBMIT_URL
syn keyword cmakeKWctest_test contained
\ APPEND
@@ -1283,6 +1994,9 @@ syn keyword cmakeKWenable_language contained
\ CUDA
\ OPTIONAL
+syn keyword cmakeKWenable_testing contained
+ \ BUILD_TESTING
+
syn keyword cmakeKWexec_program contained
\ ARGS
\ OUTPUT_VARIABLE
@@ -1292,6 +2006,7 @@ syn keyword cmakeKWexecute_process contained
\ ANSI
\ AUTO
\ COMMAND
+ \ COMMAND_ECHO
\ ENCODING
\ ERROR_FILE
\ ERROR_QUIET
@@ -1307,6 +2022,8 @@ syn keyword cmakeKWexecute_process contained
\ RESULTS_VARIABLE
\ RESULT_VARIABLE
\ RFC
+ \ STDERR
+ \ STDOUT
\ TIMEOUT
\ UTF
\ VERBATIM
@@ -1345,6 +2062,8 @@ syn keyword cmakeKWfile contained
\ CONFIGURE_DEPENDS
\ CONTENT
\ COPY
+ \ COPY_ON_ERROR
+ \ CREATE_LINK
\ DESTINATION
\ DIRECTORY_PERMISSIONS
\ DOWNLOAD
@@ -1354,6 +2073,7 @@ syn keyword cmakeKWfile contained
\ FILES_MATCHING
\ FILE_PERMISSIONS
\ FOLLOW_SYMLINKS
+ \ FOLLOW_SYMLINK_CHAIN
\ FUNCTION
\ GENERATE
\ GLOB
@@ -1365,6 +2085,7 @@ syn keyword cmakeKWfile contained
\ IGNORED
\ INACTIVITY_TIMEOUT
\ INSTALL
+ \ IS_ABSOLUTE
\ LENGTH_MAXIMUM
\ LENGTH_MINIMUM
\ LF
@@ -1379,6 +2100,7 @@ syn keyword cmakeKWfile contained
\ NETRC
\ NETRC_FILE
\ NEWLINE_CONSUME
+ \ NOT
\ NO_HEX_CONVERSION
\ NO_SOURCE_PERMISSIONS
\ OFFSET
@@ -1388,6 +2110,7 @@ syn keyword cmakeKWfile contained
\ PATTERN
\ PROCESS
\ READ
+ \ READ_SYMLINK
\ REGEX
\ RELATIVE_PATH
\ RELEASE
@@ -1395,11 +2118,14 @@ syn keyword cmakeKWfile contained
\ REMOVE_RECURSE
\ RENAME
\ REQUIRED
+ \ RESULT
\ RESULT_VARIABLE
\ SHOW_PROGRESS
+ \ SIZE
\ SSL
\ STATUS
\ STRINGS
+ \ SYMBOLIC
\ TIMESTAMP
\ TLS_CAINFO
\ TLS_VERIFY
@@ -1456,6 +2182,7 @@ syn keyword cmakeKWfind_library contained
syn keyword cmakeKWfind_package contained
\ ABI
+ \ BUNDLE
\ CMAKE_DISABLE_FIND_PACKAGE_
\ CMAKE_FIND_ROOT_PATH_BOTH
\ COMPONENTS
@@ -1464,6 +2191,7 @@ syn keyword cmakeKWfind_package contained
\ DEC
\ DVAR
\ EXACT
+ \ FRAMEWORK
\ HINTS
\ MODULE
\ NAMES
@@ -1552,24 +2280,23 @@ syn keyword cmakeKWfltk_wrap_ui contained
\ FLTK
syn keyword cmakeKWforeach contained
- \ ARGS
\ IN
\ ITEMS
\ LISTS
\ RANGE
+ \ STATUS
syn keyword cmakeKWfunction contained
\ ARGC
\ ARGN
- \ ARGS
\ ARGV
+ \ FOO
\ PARENT_SCOPE
syn keyword cmakeKWget_cmake_property contained
\ COMPONENTS
\ GLOBAL
\ MACROS
- \ VAR
\ VARIABLES
syn keyword cmakeKWget_directory_property contained
@@ -1579,18 +2306,17 @@ syn keyword cmakeKWget_directory_property contained
syn keyword cmakeKWget_filename_component contained
\ ABSOLUTE
- \ ARG_VAR
\ BASE_DIR
- \ COMP
\ DIRECTORY
\ EXT
+ \ LAST_EXT
\ NAME
\ NAME_WE
+ \ NAME_WLE
\ PATH
\ PROGRAM
\ PROGRAM_ARGS
\ REALPATH
- \ VAR
syn keyword cmakeKWget_property contained
\ BRIEF_DOCS
@@ -1620,7 +2346,6 @@ syn keyword cmakeKWget_test_property contained
\ VAR
syn keyword cmakeKWif contained
- \ ARGS
\ CMAKE_MATCH_
\ CMP
\ COMMAND
@@ -1651,7 +2376,6 @@ syn keyword cmakeKWif contained
\ STRLESS_EQUAL
\ TARGET
\ TEST
- \ THEN
\ TRUE
\ VERSION_EQUAL
\ VERSION_GREATER
@@ -1692,10 +2416,26 @@ syn keyword cmakeKWinstall contained
\ BEFORE
\ BUILD_TYPE
\ BUNDLE
+ \ CMAKE_INSTALL_BINDIR
+ \ CMAKE_INSTALL_DATADIR
+ \ CMAKE_INSTALL_DATAROOTDIR
+ \ CMAKE_INSTALL_DOCDIR
+ \ CMAKE_INSTALL_INCLUDEDIR
+ \ CMAKE_INSTALL_INFODIR
+ \ CMAKE_INSTALL_LIBDIR
+ \ CMAKE_INSTALL_LOCALEDIR
+ \ CMAKE_INSTALL_LOCALSTATEDIR
+ \ CMAKE_INSTALL_MANDIR
+ \ CMAKE_INSTALL_RUNSTATEDIR
+ \ CMAKE_INSTALL_SBINDIR
+ \ CMAKE_INSTALL_SHARESTATEDIR
+ \ CMAKE_INSTALL_SYSCONFDIR
\ CODE
\ COMPONENT
\ CONFIGURATIONS
\ CVS
+ \ DATA
+ \ DATAROOT
\ DBUILD_TYPE
\ DCOMPONENT
\ DESTDIR
@@ -1703,10 +2443,12 @@ syn keyword cmakeKWinstall contained
\ DIRECTORY
\ DIRECTORY_PERMISSIONS
\ DLL
+ \ DOC
\ EXCLUDE_FROM_ALL
\ EXPORT
\ EXPORT_ANDROID_MK
\ EXPORT_LINK_INTERFACE_LIBRARIES
+ \ EXPORT_NAME
\ FILES
\ FILES_MATCHING
\ FILE_PERMISSIONS
@@ -1716,10 +2458,14 @@ syn keyword cmakeKWinstall contained
\ GROUP_WRITE
\ IMPORTED_
\ INCLUDES
+ \ INFO
\ INSTALL_PREFIX
\ INTERFACE_INCLUDE_DIRECTORIES
\ LIBRARY
+ \ LOCALE
+ \ LOCALSTATE
\ MACOSX_BUNDLE
+ \ MAN
\ MESSAGE_NEVER
\ NAMELINK_COMPONENT
\ NAMELINK_ONLY
@@ -1737,18 +2483,25 @@ syn keyword cmakeKWinstall contained
\ PRE_INSTALL_SCRIPT
\ PRIVATE_HEADER
\ PROGRAMS
+ \ PROPERTIES
\ PUBLIC_HEADER
\ REGEX
\ RENAME
\ RESOURCE
\ RPM
+ \ RUNSTATE
\ RUNTIME
+ \ SBIN
\ SCRIPT
\ SETGID
\ SETUID
+ \ SHAREDSTATE
\ SOVERSION
+ \ STATIC
+ \ SYSCONF
\ TARGETS
\ TRUE
+ \ TYPE
\ USE_SOURCE_PERMISSIONS
\ VERSION
\ WORLD_EXECUTE
@@ -1768,7 +2521,6 @@ syn keyword cmakeKWinstall_programs contained
syn keyword cmakeKWinstall_targets contained
\ DLL
\ RUNTIME_DIRECTORY
- \ TARGETS
syn keyword cmakeKWlink_directories contained
\ AFTER
@@ -1800,6 +2552,8 @@ syn keyword cmakeKWlist contained
\ ORDER
\ OUTPUT_VARIABLE
\ PARENT_SCOPE
+ \ POP_BACK
+ \ POP_FRONT
\ PREPEND
\ REGEX
\ REMOVE_AT
@@ -1829,22 +2583,16 @@ syn keyword cmakeKWload_command contained
syn keyword cmakeKWmacro contained
\ ARGC
\ ARGN
- \ ARGS
\ ARGV
\ DEFINED
+ \ FOO
\ GREATER
\ LISTS
\ NOT
- \ _BAR
- \ _FOO
-
-syn keyword cmakeKWmake_directory contained
- \ MAKE_DIRECTORY
syn keyword cmakeKWmark_as_advanced contained
\ CLEAR
\ FORCE
- \ VAR
syn keyword cmakeKWmath contained
\ EXPR
@@ -1853,11 +2601,15 @@ syn keyword cmakeKWmath contained
syn keyword cmakeKWmessage contained
\ AUTHOR_WARNING
+ \ DEBUG
\ DEPRECATION
\ FATAL_ERROR
\ GUI
+ \ NOTICE
\ SEND_ERROR
\ STATUS
+ \ TRACE
+ \ VERBOSE
\ WARNING
syn keyword cmakeKWoption contained
@@ -1886,19 +2638,21 @@ syn keyword cmakeKWproject contained
\ _VERSION_PATCH
\ _VERSION_TWEAK
+syn keyword cmakeKWqt_wrap_cpp contained
+ \ AUTOMOC
+
+syn keyword cmakeKWqt_wrap_ui contained
+ \ AUTOUIC
+
syn keyword cmakeKWremove contained
- \ REMOVE_ITEM
\ VALUE
\ VAR
syn keyword cmakeKWseparate_arguments contained
\ MSDN
- \ NATIVE
\ NATIVE_COMMAND
\ UNIX_COMMAND
- \ WINDOWS
\ WINDOWS_COMMAND
- \ _COMMAND
syn keyword cmakeKWset contained
\ BOOL
@@ -1912,6 +2666,7 @@ syn keyword cmakeKWset contained
\ STRINGS
syn keyword cmakeKWset_directory_properties contained
+ \ DIRECTORY
\ PROPERTIES
syn keyword cmakeKWset_property contained
@@ -1929,6 +2684,7 @@ syn keyword cmakeKWset_property contained
syn keyword cmakeKWset_source_files_properties contained
\ PROPERTIES
+ \ SOURCE
syn keyword cmakeKWset_target_properties contained
\ PROPERTIES
@@ -1936,6 +2692,7 @@ syn keyword cmakeKWset_target_properties contained
syn keyword cmakeKWset_tests_properties contained
\ PROPERTIES
+ \ TEST
syn keyword cmakeKWsource_group contained
\ FILES
@@ -1974,6 +2731,7 @@ syn keyword cmakeKWstring contained
\ RANDOM
\ RANDOM_SEED
\ REGEX
+ \ REPEAT
\ REPLACE
\ REVERSE
\ RFC
@@ -2070,7 +2828,6 @@ syn keyword cmakeKWtarget_link_libraries contained
\ LINK_PUBLIC
\ OBJECT
\ OLD
- \ OSX
\ PRIVATE
\ PUBLIC
\ SHARED
@@ -2091,6 +2848,7 @@ syn keyword cmakeKWtarget_link_options contained
\ PRIVATE
\ PUBLIC
\ SHELL
+ \ STATIC_LIBRARY_OPTIONS
\ UNIX_COMMAND
\ _LINKER_WRAPPER_FLAG
\ _LINKER_WRAPPER_FLAG_SEP
@@ -2122,15 +2880,21 @@ syn keyword cmakeKWtry_compile contained
\ DEFINED
\ DLINK_LIBRARIES
\ DVAR
+ \ EXECUTABLE
\ FALSE
+ \ GHS
\ INCLUDE_DIRECTORIES
\ LANG
\ LINK_DIRECTORIES
\ LINK_LIBRARIES
+ \ LINK_OPTIONS
+ \ MULTI
\ NOT
\ OUTPUT_VARIABLE
- \ RESULT_VAR
+ \ PRIVATE
\ SOURCES
+ \ STATIC_LIBRARY
+ \ STATIC_LIBRARY_OPTIONS
\ TRUE
\ TYPE
\ VALUE
@@ -2143,7 +2907,6 @@ syn keyword cmakeKWtry_run contained
\ CMAKE_FLAGS
\ COMPILE_DEFINITIONS
\ COMPILE_OUTPUT_VARIABLE
- \ COMPILE_RESULT_VAR
\ DLINK_LIBRARIES
\ DVAR
\ FAILED_TO_RUN
@@ -2151,15 +2914,14 @@ syn keyword cmakeKWtry_run contained
\ INCLUDE_DIRECTORIES
\ LINK_DIRECTORIES
\ LINK_LIBRARIES
+ \ LINK_OPTIONS
\ RUN_OUTPUT_VARIABLE
- \ RUN_RESULT_VAR
\ TRUE
\ TYPE
\ VALUE
\ __TRYRUN_OUTPUT
syn keyword cmakeKWunset contained
- \ LD_LIBRARY_PATH
\ PARENT_SCOPE
\ VAR
@@ -2175,9 +2937,6 @@ syn keyword cmakeKWvariable_requires contained
syn keyword cmakeKWvariable_watch contained
\ COMMAND
-syn keyword cmakeKWwhile contained
- \ ARGS
-
syn keyword cmakeKWwrite_file contained
\ APPEND
\ CONFIGURE_FILE
@@ -2188,20 +2947,26 @@ syn keyword cmakeKWwrite_file contained
syn keyword cmakeGeneratorExpressions contained
\ AND
\ ANGLE
+ \ ARCHIVE_OUTPUT_NAME
+ \ ARCHIVE_OUTPUT_NAME_
+ \ BAR
\ BOOL
\ BUILD_INTERFACE
\ CMAKE_
- \ CMAKE_CXX_COMPILER_VERSION
\ COMMA
\ COMMAND
\ COMPILE_DEFINITIONS
\ COMPILE_FEATURES
\ COMPILE_LANGUAGE
+ \ COMPILE_LANG_AND_ID
\ COMPILING_CUDA
- \ COMPILING_CXX
+ \ COMPILING_CXX_WITH_CLANG
+ \ COMPILING_CXX_WITH_INTEL
+ \ COMPILING_C_WITH_CLANG
\ CONFIG
\ CONFIGURATION
- \ CUDA
+ \ CUDA_COMPILER_ID
+ \ CUDA_COMPILER_VERSION
\ CUSTOM_KEYS
\ CXX_COMPILER_ID
\ CXX_COMPILER_VERSION
@@ -2210,13 +2975,21 @@ syn keyword cmakeGeneratorExpressions contained
\ C_COMPILER_VERSION
\ C_STANDARD
\ DEBUG_MODE
+ \ DEBUG_POSTFIX
+ \ EXCLUDE
\ EXPORT
+ \ FALSE
+ \ FILTER
\ FOO_EXTRA_THINGS
\ Fortran_COMPILER_ID
\ Fortran_COMPILER_VERSION
+ \ GENERATE
\ GENEX_EVAL
\ GNU
\ IF
+ \ IGNORE
+ \ IMPORT_PREFIX
+ \ IMPORT_SUFFIX
\ INCLUDE_DIRECTORIES
\ INSTALL_INTERFACE
\ INSTALL_PREFIX
@@ -2224,22 +2997,31 @@ syn keyword cmakeGeneratorExpressions contained
\ IN_LIST
\ JOIN
\ LANG
+ \ LANG_COMPILER_ID
+ \ LIBRARY_OUTPUT_NAME
+ \ LIBRARY_OUTPUT_NAME_
\ LINK_LIBRARIES
\ LINK_ONLY
\ LOWER_CASE
\ MAKE_C_IDENTIFIER
\ MAP_IMPORTED_CONFIG_
- \ MSYS
+ \ NO
\ NOT
- \ OBJECT_LIBRARY
+ \ OFF
\ OLD_COMPILER
+ \ OUTPUT_NAME
+ \ OUTPUT_NAME_
\ PDB_NAME
\ PDB_NAME_
\ PDB_OUTPUT_DIRECTORY
\ PDB_OUTPUT_DIRECTORY_
\ PLATFORM_ID
+ \ POSIX
\ PRIVATE
\ PUBLIC
+ \ REMOVE_DUPLICATES
+ \ RUNTIME_OUTPUT_NAME
+ \ RUNTIME_OUTPUT_NAME_
\ SDK
\ SEMICOLON
\ SHELL_PATH
@@ -2248,16 +3030,22 @@ syn keyword cmakeGeneratorExpressions contained
\ TARGET_BUNDLE_DIR
\ TARGET_EXISTS
\ TARGET_FILE
+ \ TARGET_FILE_BASE_NAME
\ TARGET_FILE_DIR
\ TARGET_FILE_NAME
+ \ TARGET_FILE_PREFIX
+ \ TARGET_FILE_SUFFIX
\ TARGET_GENEX_EVAL
\ TARGET_LINKER_FILE
+ \ TARGET_LINKER_FILE_BASE_NAME
\ TARGET_LINKER_FILE_DIR
\ TARGET_LINKER_FILE_NAME
- \ TARGET_NAME
+ \ TARGET_LINKER_FILE_PREFIX
+ \ TARGET_LINKER_FILE_SUFFIX
\ TARGET_NAME_IF_EXISTS
\ TARGET_OBJECTS
\ TARGET_PDB_FILE
+ \ TARGET_PDB_FILE_BASE_NAME
\ TARGET_PDB_FILE_DIR
\ TARGET_PDB_FILE_NAME
\ TARGET_POLICY
@@ -2271,6 +3059,7 @@ syn keyword cmakeGeneratorExpressions contained
\ VERSION_GREATER_EQUAL
\ VERSION_LESS
\ VERSION_LESS_EQUAL
+ \ _POSTFIX
syn case ignore
@@ -2446,7 +3235,6 @@ hi def link cmakeKWadd_link_options ModeMsg
hi def link cmakeKWadd_subdirectory ModeMsg
hi def link cmakeKWadd_test ModeMsg
hi def link cmakeKWbuild_command ModeMsg
-hi def link cmakeKWbuild_name ModeMsg
hi def link cmakeKWcmake_host_system_information ModeMsg
hi def link cmakeKWcmake_minimum_required ModeMsg
hi def link cmakeKWcmake_parse_arguments ModeMsg
@@ -2465,6 +3253,7 @@ hi def link cmakeKWctest_update ModeMsg
hi def link cmakeKWctest_upload ModeMsg
hi def link cmakeKWdefine_property ModeMsg
hi def link cmakeKWenable_language ModeMsg
+hi def link cmakeKWenable_testing ModeMsg
hi def link cmakeKWexec_program ModeMsg
hi def link cmakeKWexecute_process ModeMsg
hi def link cmakeKWexport ModeMsg
@@ -2499,12 +3288,13 @@ hi def link cmakeKWlist ModeMsg
hi def link cmakeKWload_cache ModeMsg
hi def link cmakeKWload_command ModeMsg
hi def link cmakeKWmacro ModeMsg
-hi def link cmakeKWmake_directory ModeMsg
hi def link cmakeKWmark_as_advanced ModeMsg
hi def link cmakeKWmath ModeMsg
hi def link cmakeKWmessage ModeMsg
hi def link cmakeKWoption ModeMsg
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 cmakeKWseparate_arguments ModeMsg
hi def link cmakeKWset ModeMsg
@@ -2530,7 +3320,6 @@ hi def link cmakeKWunset ModeMsg
hi def link cmakeKWuse_mangled_mesa ModeMsg
hi def link cmakeKWvariable_requires ModeMsg
hi def link cmakeKWvariable_watch ModeMsg
-hi def link cmakeKWwhile ModeMsg
hi def link cmakeKWwrite_file ModeMsg
" Manually added - difficult to parse out of documentation
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
index dc9f0bae6..78e22cc85 100644
--- a/CMakeCPack.cmake
+++ b/CMakeCPack.cmake
@@ -102,9 +102,6 @@ if(CMake_INSTALL_COMPONENTS)
if(WIN32 AND NOT CYGWIN)
list(APPEND _CPACK_IFW_COMPONENTS_ALL cmcldeps)
endif()
- if(APPLE)
- list(APPEND _CPACK_IFW_COMPONENTS_ALL cmakexbuild)
- endif()
if(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
set(_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME
${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in
index a08c97d04..2a4bcc589 100644
--- a/CMakeCPackOptions.cmake.in
+++ b/CMakeCPackOptions.cmake.in
@@ -109,16 +109,6 @@ if(CPACK_GENERATOR MATCHES "IFW")
set(CPACK_IFW_COMPONENT_CMCLDEPS_VERSION
"@CMake_IFW_ROOT_COMPONENT_VERSION@")
- set(CPACK_COMPONENT_CMAKEXBUILD_DISPLAY_NAME "cmakexbuild")
- set(CPACK_COMPONENT_CMAKEXBUILD_DESCRIPTION
- "The \"cmakexbuild\" executable is a wrapper program for \"xcodebuild\"")
- set(CPACK_COMPONENT_CMAKEXBUILD_REQUIRED TRUE)
- set(CPACK_COMPONENT_CMAKEXBUILD_GROUP Tools)
- set(CPACK_IFW_COMPONENT_CMAKEXBUILD_NAME "CMakeXBuild")
- set(CPACK_IFW_COMPONENT_CMAKEXBUILD_PRIORITY 85)
- set(CPACK_IFW_COMPONENT_CMAKEXBUILD_VERSION
- "@CMake_IFW_ROOT_COMPONENT_VERSION@")
-
# Dialogs
set(CPACK_COMPONENT_GROUP_DIALOGS_DISPLAY_NAME "Interactive Dialogs")
set(CPACK_COMPONENT_GROUP_DIALOGS_DESCRIPTION
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd130ec36..51a1d8bc0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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.12 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.1...3.14 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)
@@ -139,7 +139,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
# Allow the user to enable/disable all system utility library options by
# defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}.
- set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBRHASH LIBUV ZLIB)
+ set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBRHASH LIBUV ZLIB ZSTD)
foreach(util ${UTILITIES})
if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util}
AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES)
@@ -173,6 +173,8 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
"${CMAKE_USE_SYSTEM_LIBRARY_ZLIB}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE;NOT CMAKE_USE_SYSTEM_CURL" ON)
CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_BZIP2 "Use system-installed bzip2"
"${CMAKE_USE_SYSTEM_LIBRARY_BZIP2}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_ZSTD "Use system-installed zstd"
+ "${CMAKE_USE_SYSTEM_LIBRARY_ZSTD}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_LIBLZMA "Use system-installed liblzma"
"${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}")
@@ -445,14 +447,6 @@ macro (CMAKE_BUILD_UTILITIES)
endif()
#---------------------------------------------------------------------
- # Build Compress library for CTest.
- set(CMAKE_COMPRESS_INCLUDES
- "${CMAKE_CURRENT_BINARY_DIR}/Utilities/cmcompress")
- set(CMAKE_COMPRESS_LIBRARIES "cmcompress")
- add_subdirectory(Utilities/cmcompress)
- CMAKE_SET_TARGET_FOLDER(cmcompress "Utilities/3rdParty")
-
- #---------------------------------------------------------------------
# Build expat library for CMake, CTest, and libarchive.
if(CMAKE_USE_SYSTEM_EXPAT)
find_package(EXPAT)
@@ -484,6 +478,17 @@ macro (CMAKE_BUILD_UTILITIES)
endif()
#---------------------------------------------------------------------
+ # Build or use system zstd for libarchive.
+ if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(NOT CMAKE_USE_SYSTEM_ZSTD)
+ set(ZSTD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmzstd")
+ set(ZSTD_LIBRARY cmzstd)
+ add_subdirectory(Utilities/cmzstd)
+ CMAKE_SET_TARGET_FOLDER(cmzstd "Utilities/3rdParty")
+ endif()
+ endif()
+
+ #---------------------------------------------------------------------
# Build or use system liblzma for libarchive.
if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
if(CMAKE_USE_SYSTEM_LIBLZMA)
@@ -546,6 +551,10 @@ macro (CMAKE_BUILD_UTILITIES)
message(FATAL_ERROR
"CMAKE_USE_SYSTEM_JSONCPP is ON but a JsonCpp is not found!")
endif()
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+ set_property(TARGET JsonCpp::JsonCpp APPEND PROPERTY
+ INTERFACE_COMPILE_OPTIONS -Wno-deprecated-declarations)
+ endif()
set(CMAKE_JSONCPP_LIBRARIES JsonCpp::JsonCpp)
else()
set(CMAKE_JSONCPP_LIBRARIES cmjsoncpp)
@@ -813,4 +822,10 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE)
# Install auxiliary files integrating with other tools.
add_subdirectory(Auxiliary)
+
+ # Optionally sign installed binaries.
+ if(CMake_INSTALL_SIGNTOOL)
+ configure_file(Source/CMakeInstallSignTool.cmake.in Source/CMakeInstallSignTool.cmake @ONLY)
+ install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/Source/CMakeInstallSignTool.cmake)
+ endif()
endif()
diff --git a/CompileFlags.cmake b/CompileFlags.cmake
index 5d0e14493..91f2adffe 100644
--- a/CompileFlags.cmake
+++ b/CompileFlags.cmake
@@ -8,11 +8,16 @@ if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel")
set(_INTEL_WINDOWS 1)
endif()
+if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(_CLANG_MSVC_WINDOWS 1)
+endif()
+
# Disable deprecation warnings for standard C functions.
# really only needed for newer versions of VS, but should
# not hurt other versions, and this will work into the
# future
-if(MSVC OR _INTEL_WINDOWS)
+if(MSVC OR _INTEL_WINDOWS OR _CLANG_MSVC_WINDOWS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
else()
endif()
@@ -21,6 +26,10 @@ if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stack:10000000")
endif()
+if(_CLANG_MSVC_WINDOWS AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Xlinker -stack:20000000")
+endif()
+
#silence duplicate symbol warnings on AIX
if(CMAKE_SYSTEM_NAME MATCHES "AIX")
if(NOT CMAKE_COMPILER_IS_GNUCXX)
@@ -44,6 +53,15 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^parisc")
endif()
endif()
+# Workaround for TOC Overflow on ppc64
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "powerpc")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-bbigtoc")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-multi-toc")
+endif()
+
if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND
NOT DEFINED CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 9bf0d8720..ed321fcef 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -23,6 +23,7 @@ The first signature is for adding a custom command to produce an output:
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
+ [JOB_POOL job_pool]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS])
@@ -144,6 +145,13 @@ The options are:
Note that the ``IMPLICIT_DEPENDS`` option is currently supported
only for Makefile generators and will be ignored by other generators.
+``JOB_POOL``
+ Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
+ generator. Incompatible with ``USES_TERMINAL``, which implies
+ the ``console`` pool.
+ Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+ an error by ninja at build time.
+
``MAIN_DEPENDENCY``
Specify the primary input source file to the command. This is
treated just like any value given to the ``DEPENDS`` option
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index c63dd230d..08b95168b 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -11,6 +11,7 @@ Add a target with no output so it will always be built.
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
+ [JOB_POOL job_pool]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])
@@ -97,6 +98,13 @@ The options are:
``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
to be properly expanded.
+``JOB_POOL``
+ Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
+ generator. Incompatible with ``USES_TERMINAL``, which implies
+ the ``console`` pool.
+ Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+ an error by ninja at build time.
+
``SOURCES``
Specify additional source files to be included in the custom target.
Specified source files will be added to IDE project files for
diff --git a/Help/command/add_definitions.rst b/Help/command/add_definitions.rst
index 39a43f4f4..d06b01c9a 100644
--- a/Help/command/add_definitions.rst
+++ b/Help/command/add_definitions.rst
@@ -20,7 +20,7 @@ preprocessor definitions.
* Use :command:`include_directories` to add include directories.
* Use :command:`add_compile_options` to add other options.
-Flags beginning in -D or /D that look like preprocessor definitions are
+Flags beginning in ``-D`` or ``/D`` that look like preprocessor definitions are
automatically added to the :prop_dir:`COMPILE_DEFINITIONS` directory
property for the current directory. Definitions with non-trivial values
may be left in the set of flags instead of being converted for reasons of
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index ec6cb9d9a..7274e4474 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -80,15 +80,26 @@ option extends visibility. It may be referenced like any target built
within the project. ``IMPORTED`` libraries are useful for convenient
reference from commands like :command:`target_link_libraries`. Details
about the imported library are specified by setting properties whose names
-begin in ``IMPORTED_`` and ``INTERFACE_``. The most important such
-property is :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
-variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
-location of the main library file on disk. Or, for object libraries,
-:prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
-specifies the locations of object files on disk.
+begin in ``IMPORTED_`` and ``INTERFACE_``.
+
+The most important properties are:
+
+* :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
+ variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
+ location of the main library file on disk.
+* :prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
+ for object libraries, specifies the locations of object files on disk.
+* :prop_tgt:`PUBLIC_HEADER` files to be installed during :command:`install` invocation
+
See documentation of the ``IMPORTED_*`` and ``INTERFACE_*`` properties
for more information.
+An ``UNKNOWN`` library type is typically only used in the implementation of
+:ref:`Find Modules`. It allows the path to an imported library (often found
+using the :command:`find_library` command) to be used without having to know
+what type of library it is. This is especially useful on Windows where a
+static library and a DLL's import library both have the same file extension.
+
Object Libraries
^^^^^^^^^^^^^^^^
diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst
index 1b02beebe..a83005b06 100644
--- a/Help/command/add_link_options.rst
+++ b/Help/command/add_link_options.rst
@@ -1,20 +1,25 @@
add_link_options
----------------
-Add options to the link of shared library, module and executable targets.
+Add options to the link step for executable, shared library or module
+library targets in the current directory and below that are added after
+this command is invoked.
.. code-block:: cmake
add_link_options(<option> ...)
-Adds options to the link step for targets in the current directory and below
-that are added after this command is invoked. See documentation of the
+This command can be used to add any link options, but alternative commands
+exist to add libraries (:command:`target_link_libraries` or
+:command:`link_libraries`). See documentation of the
:prop_dir:`directory <LINK_OPTIONS>` and
:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
-This command can be used to add any options, but alternative commands
-exist to add libraries (:command:`target_link_libraries` or
-:command:`link_libraries`).
+.. note::
+
+ This command cannot be used to add options for static library targets,
+ since they do not use a linker. To add archiver or MSVC librarian flags,
+ see the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
Arguments to ``add_link_options`` may use "generator expressions" with
the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
index a8c257d8b..46b9b63c5 100644
--- a/Help/command/add_test.rst
+++ b/Help/command/add_test.rst
@@ -55,7 +55,8 @@ file produced by target ``myexe``.
CMake will generate tests only if the :command:`enable_testing`
command has been invoked. The :module:`CTest` module invokes the
- command automatically when the ``BUILD_TESTING`` option is ``ON``.
+ command automatically unless the ``BUILD_TESTING`` option is turned
+ ``OFF``.
---------------------------------------------------------------------
diff --git a/Help/command/aux_source_directory.rst b/Help/command/aux_source_directory.rst
index e0af66591..9619f357f 100644
--- a/Help/command/aux_source_directory.rst
+++ b/Help/command/aux_source_directory.rst
@@ -11,14 +11,14 @@ Collects the names of all the source files in the specified directory
and stores the list in the ``<variable>`` provided. This command is
intended to be used by projects that use explicit template
instantiation. Template instantiation files can be stored in a
-"Templates" subdirectory and collected automatically using this
+``Templates`` subdirectory and collected automatically using this
command to avoid manually listing all instantiations.
It is tempting to use this command to avoid writing the list of source
files for a library or executable target. While this seems to work,
there is no way for CMake to generate a build system that knows when a
new source file has been added. Normally the generated build system
-knows when it needs to rerun CMake because the CMakeLists.txt file is
+knows when it needs to rerun CMake because the ``CMakeLists.txt`` file is
modified to add a new source. When the source is just added to the
directory without modifying this file, one would have to manually
rerun CMake to generate a build system incorporating the new file.
diff --git a/Help/command/build_command.rst b/Help/command/build_command.rst
index b83edaf57..6659005be 100644
--- a/Help/command/build_command.rst
+++ b/Help/command/build_command.rst
@@ -14,7 +14,7 @@ This is mainly intended for internal use by the :module:`CTest` module.
Sets the given ``<variable>`` to a command-line string of the form::
- <cmake> --build . [--config <config>] [--target <target>] [-- -i]
+ <cmake> --build . [--config <config>] [--target <target>...] [-- -i]
where ``<cmake>`` is the location of the :manual:`cmake(1)` command-line
tool, and ``<config>`` and ``<target>`` are the values provided to the
diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst
index c8327e286..fcd36d0a3 100644
--- a/Help/command/cmake_parse_arguments.rst
+++ b/Help/command/cmake_parse_arguments.rst
@@ -55,12 +55,17 @@ For the ``<options>`` keywords, these will always be defined,
to ``TRUE`` or ``FALSE``, whether the option is in the argument list or not.
All remaining arguments are collected in a variable
-``<prefix>_UNPARSED_ARGUMENTS`` that will be undefined if all argument
-where recognized. This can be checked afterwards to see
+``<prefix>_UNPARSED_ARGUMENTS`` that will be undefined if all arguments
+were recognized. This can be checked afterwards to see
whether your macro was called with unrecognized parameters.
-As an example here a ``my_install()`` macro, which takes similar arguments
-as the real :command:`install` command:
+``<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:
.. code-block:: cmake
@@ -77,7 +82,7 @@ Assume ``my_install()`` has been called like this:
.. code-block:: cmake
- my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
+ my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
After the ``cmake_parse_arguments`` call the macro will have set or undefined
the following variables::
@@ -89,13 +94,16 @@ the following variables::
MY_INSTALL_TARGETS = "foo;bar"
MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used
MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
+ MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS"
+ # No value for "CONFIGURATIONS" given
You can then continue and process these variables.
-Keywords terminate lists of values, e.g. if directly after a
-one_value_keyword another recognized keyword follows, this is
+Keywords terminate lists of values, e.g. if directly after a
+``one_value_keyword`` another recognized keyword follows, this is
interpreted as the beginning of the new option. E.g.
``my_install(TARGETS foo DESTINATION OPTIONAL)`` would result in
``MY_INSTALL_DESTINATION`` set to ``"OPTIONAL"``, but as ``OPTIONAL``
-is a keyword itself ``MY_INSTALL_DESTINATION`` will be empty and
-``MY_INSTALL_OPTIONAL`` will therefore be set to ``TRUE``.
+is a keyword itself ``MY_INSTALL_DESTINATION`` will be empty (but added
+to ``MY_INSTALL_KEYWORDS_MISSING_VALUES``) and ``MY_INSTALL_OPTIONAL`` will
+therefore be set to ``TRUE``.
diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst
index a80f98244..4bc7807bb 100644
--- a/Help/command/cmake_policy.rst
+++ b/Help/command/cmake_policy.rst
@@ -80,7 +80,7 @@ CMake Policy Stack
^^^^^^^^^^^^^^^^^^
CMake keeps policy settings on a stack, so changes made by the
-cmake_policy command affect only the top of the stack. A new entry on
+``cmake_policy`` command affect only the top of the stack. A new entry on
the policy stack is managed automatically for each subdirectory to
protect its parents and siblings. CMake also manages a new entry for
scripts loaded by :command:`include` and :command:`find_package` commands
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
index fba03fd58..983fc20ce 100644
--- a/Help/command/ctest_submit.rst
+++ b/Help/command/ctest_submit.rst
@@ -7,6 +7,7 @@ Perform the :ref:`CTest Submit Step` as a :ref:`Dashboard Client`.
ctest_submit([PARTS <part>...] [FILES <file>...]
[SUBMIT_URL <url>]
+ [BUILD_ID <result-var>]
[HTTPHEADER <header>]
[RETRY_COUNT <count>]
[RETRY_DELAY <delay>]
@@ -44,9 +45,21 @@ The options are:
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>``
+ Store in the ``<result-var>`` variable the ID assigned to this build by
+ CDash.
+
``HTTPHEADER <HTTP-header>``
Specify HTTP header to be included in the request to CDash during submission.
- This suboption can be repeated several times.
+ For example, CDash can be configured to only accept submissions from
+ authenticated clients. In this case, you should provide a bearer token in your
+ header:
+
+ .. code-block:: cmake
+
+ ctest_submit(HTTPHEADER "Authorization: Bearer <auth-token>")
+
+ This suboption can be repeated several times for multiple headers.
``RETRY_COUNT <count>``
Specify how many times to retry a timed-out submission.
@@ -86,5 +99,6 @@ 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``, ``HTTPHEADER``, ``RETRY_COUNT``,
-``RETRY_DELAY``, ``RETURN_VALUE`` and ``QUIET`` options as described above.
+This signature accepts the ``SUBMIT_URL``, ``BUILD_ID``, ``HTTPHEADER``,
+``RETRY_COUNT``, ``RETRY_DELAY``, ``RETURN_VALUE`` and ``QUIET`` options
+as described above.
diff --git a/Help/command/ctest_update.rst b/Help/command/ctest_update.rst
index df1a4e560..96a11c913 100644
--- a/Help/command/ctest_update.rst
+++ b/Help/command/ctest_update.rst
@@ -35,4 +35,5 @@ The options are:
The update always follows the version control branch currently checked
out in the source directory. See the :ref:`CTest Update Step`
-documentation for more information.
+documentation for information about variables that change the behavior
+of ``ctest_update()``.
diff --git a/Help/command/enable_testing.rst b/Help/command/enable_testing.rst
index e2028d21b..3ac1a198a 100644
--- a/Help/command/enable_testing.rst
+++ b/Help/command/enable_testing.rst
@@ -7,7 +7,14 @@ Enable testing for current directory and below.
enable_testing()
-Enables testing for this directory and below. See also the
-:command:`add_test` command. Note that ctest expects to find a test file
-in the build directory root. Therefore, this command should be in the
-source directory root.
+Enables testing for this directory and below.
+
+This command should be in the source directory root
+because ctest expects to find a test file in the build
+directory root.
+
+This command is automatically invoked when the :module:`CTest`
+module is included, except if the ``BUILD_TESTING`` option is
+turned off.
+
+See also the :command:`add_test` command.
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
index 3a56dce97..14f879d03 100644
--- a/Help/command/execute_process.rst
+++ b/Help/command/execute_process.rst
@@ -18,11 +18,14 @@ Execute one or more child processes.
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
+ [COMMAND_ECHO <where>]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>])
-Runs the given sequence of one or more commands in parallel with the standard
+Runs the given sequence of one or more commands.
+
+Commands are executed concurrently as a pipeline, with the standard
output of each process piped to the standard input of the next.
A single standard error pipe is used for all processes.
@@ -46,8 +49,9 @@ Options:
the child processes.
``TIMEOUT``
- The child processes will be terminated if they do not finish in the
- specified number of seconds (fractions are allowed).
+ After the specified number of seconds (fractions allowed), all unfinished
+ child processes will be terminated, and the ``RESULT_VARIABLE`` will be
+ set to a string mentioning the "timeout".
``RESULT_VARIABLE``
The variable will be set to contain the result of last child process.
@@ -56,9 +60,9 @@ Options:
``RESULTS_VARIABLE <variable>``
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 from the
- corresponding child or a string describing an error condition.
+ :ref:`semicolon-separated list <CMake Language Lists>`, in order of the
+ given ``COMMAND`` arguments. Each entry will be an integer return code
+ from the corresponding child or a string describing an error condition.
``OUTPUT_VARIABLE``, ``ERROR_VARIABLE``
The variable named will be set with the contents of the standard output
@@ -74,6 +78,12 @@ Options:
``OUTPUT_QUIET``, ``ERROR_QUIET``
The standard output or standard error results will be quietly ignored.
+``COMMAND_ECHO <where>``
+ 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>``
On Windows, the encoding that is used to decode output from the process.
Ignored on other platforms.
diff --git a/Help/command/export.rst b/Help/command/export.rst
index b255ee84e..2ca705616 100644
--- a/Help/command/export.rst
+++ b/Help/command/export.rst
@@ -54,7 +54,7 @@ unspecified.
export(PACKAGE <PackageName>)
Store the current build directory in the CMake user package registry
-for package ``<PackageName>``. The find_package command may consider the
+for package ``<PackageName>``. The :command:`find_package` command may consider the
directory while searching for package ``<PackageName>``. This helps dependent
projects find and use a package from the current project's build tree
without help from the user. Note that the entry in the package
@@ -62,8 +62,13 @@ registry that this command creates works only in conjunction with a
package configuration file (``<PackageName>Config.cmake``) that works with the
build tree. In some cases, for example for packaging and for system
wide installations, it is not desirable to write the user package
-registry. If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable
-is enabled, the ``export(PACKAGE)`` command will do nothing.
+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.
.. code-block:: cmake
diff --git a/Help/command/file.rst b/Help/command/file.rst
index 465e56743..f99021ef6 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -292,7 +292,8 @@ 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.
+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.
.. _MAKE_DIRECTORY:
@@ -311,6 +312,7 @@ Create the given directories and their parents as needed.
[FILE_PERMISSIONS <permissions>...]
[DIRECTORY_PERMISSIONS <permissions>...]
[NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
+ [FOLLOW_SYMLINK_CHAIN]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS <permissions>...]] [...])
@@ -324,6 +326,32 @@ 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:
+
+* ``/opt/foo/lib/libfoo.so.1.2.3``
+* ``/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3``
+* ``/opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2``
+* ``/opt/foo/lib/libfoo.so -> libfoo.so.1``
+
+and you do:
+
+.. code-block:: cmake
+
+ file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN)
+
+This will install all of the symlinks and ``libfoo.so.1.2.3`` itself into
+``lib``.
+
See the :command:`install(DIRECTORY)` command for documentation of
permissions, ``FILES_MATCHING``, ``PATTERN``, ``REGEX``, and
``EXCLUDE`` options. Copying directories preserves the structure
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 54d5f68fe..e5e5b2cf6 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -59,6 +59,13 @@ for finding the package, checking the version, and producing any needed
messages. Some find-modules provide limited or no support for versioning;
check the module documentation.
+If the ``MODULE`` option is not specfied in the above signature,
+CMake first searches for the package using Module mode. Then, if the
+package is not found, it searches again using Config mode. A user
+may set the variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` to
+``TRUE`` to direct CMake first search using Config mode before falling
+back to Module mode.
+
Full Signature and Config Mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,7 +187,7 @@ sets these variables:
These variables are checked by the ``find_package`` command to determine
whether the configuration file provides an acceptable version. They
-are not available after the find_package call returns. If the version
+are not available after the ``find_package`` call returns. If the version
is acceptable the following variables are set:
``<PackageName>_VERSION``
@@ -220,8 +227,8 @@ Search Procedure
CMake constructs a set of possible installation prefixes for the
package. Under each prefix several directories are searched for a
configuration file. The tables below show the directories searched.
-Each entry is meant for installation trees following Windows (W), UNIX
-(U), or Apple (A) conventions::
+Each entry is meant for installation trees following Windows (``W``), UNIX
+(``U``), or Apple (``A``) conventions::
<prefix>/ (W)
<prefix>/(cmake|CMake)/ (W)
@@ -234,8 +241,8 @@ Each entry is meant for installation trees following Windows (W), UNIX
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/ (W/U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (W/U)
-On systems supporting macOS Frameworks and Application Bundles the
-following directories are searched for frameworks or bundles
+On systems supporting macOS :prop_tgt:`FRAMEWORK` and :prop_tgt:`BUNDLE`, the
+following directories are searched for Frameworks or Application Bundles
containing a configuration file::
<prefix>/<name>.framework/Resources/ (A)
@@ -262,16 +269,16 @@ that order).
* The ``lib`` path is always searched.
If ``PATH_SUFFIXES`` is specified, the suffixes are appended to each
-(W) or (U) directory entry one-by-one.
+(``W``) or (``U``) directory entry one-by-one.
This set of directories is intended to work in cooperation with
projects that provide configuration files in their installation trees.
-Directories above marked with (W) are intended for installations on
+Directories above marked with (``W``) are intended for installations on
Windows where the prefix may point at the top of an application's
-installation directory. Those marked with (U) are intended for
+installation directory. Those marked with (``U``) are intended for
installations on UNIX platforms where the prefix is shared by multiple
-packages. This is merely a convention, so all (W) and (U) directories
-are still searched on all platforms. Directories marked with (A) are
+packages. This is merely a convention, so all (``W``) and (``U``) directories
+are still searched on all platforms. Directories marked with (``A``) are
intended for installations on Apple platforms. The
:variable:`CMAKE_FIND_FRAMEWORK` and :variable:`CMAKE_FIND_APPBUNDLE`
variables determine the order of preference.
diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst
index 58bf7412b..96764a3b9 100644
--- a/Help/command/get_cmake_property.rst
+++ b/Help/command/get_cmake_property.rst
@@ -9,7 +9,7 @@ Get a global property of the CMake instance.
Gets a global property from the CMake instance. The value of
the ``<property>`` is stored in the variable ``<var>``.
-If the property is not found, ``<var>`` will be set to ``"NOTFOUND"``.
+If the property is not found, ``<var>`` will be set to ``NOTFOUND``.
See the :manual:`cmake-properties(7)` manual for available properties.
See also the :command:`get_property` command ``GLOBAL`` option.
diff --git a/Help/command/get_target_property.rst b/Help/command/get_target_property.rst
index 43276811d..11e07eabe 100644
--- a/Help/command/get_target_property.rst
+++ b/Help/command/get_target_property.rst
@@ -11,7 +11,7 @@ Get a property from a target. The value of the property is stored in
the variable ``VAR``. If the target property is not found, the behavior
depends on whether it has been defined to be an ``INHERITED`` property
or not (see :command:`define_property`). Non-inherited properties will
-set ``VAR`` to "NOTFOUND", whereas inherited properties will search the
+set ``VAR`` to ``NOTFOUND``, whereas inherited properties will search the
relevant parent scope as described for the :command:`define_property`
command and if still unable to find the property, ``VAR`` will be set to
an empty string.
diff --git a/Help/command/if.rst b/Help/command/if.rst
index a48a0faac..d8e3a45da 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -88,7 +88,9 @@ Possible conditions are:
``if(EXISTS path-to-file-or-directory)``
True if the named file or directory exists. Behavior is well-defined
- only for full paths.
+ 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.
``if(file1 IS_NEWER_THAN file2)``
True if ``file1`` is newer than ``file2`` or if one of the two files doesn't
@@ -227,7 +229,7 @@ above. The result is ``OFF`` which is false. However, if we remove the
if(var2)
-which is true because ``var2`` is defined to "var1" which is not a false
+which is true because ``var2`` is defined to ``var1`` which is not a false
constant.
Automatic evaluation applies in the other cases whenever the
diff --git a/Help/command/include_external_msproject.rst b/Help/command/include_external_msproject.rst
index 375baf2f9..540a13af8 100644
--- a/Help/command/include_external_msproject.rst
+++ b/Help/command/include_external_msproject.rst
@@ -13,11 +13,11 @@ Include an external Microsoft project file in a workspace.
Includes an external Microsoft project in the generated workspace
file. Currently does nothing on UNIX. This will create a target
-named [projectname]. This can be used in the :command:`add_dependencies`
+named ``[projectname]``. This can be used in the :command:`add_dependencies`
command to make things depend on the external project.
``TYPE``, ``GUID`` and ``PLATFORM`` are optional parameters that allow one to
-specify the type of project, id (GUID) of the project and the name of
+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).
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 6910d6df0..ab6fef664 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -99,6 +99,7 @@ Windows platforms are unaffected.
Installing Targets
^^^^^^^^^^^^^^^^^^
+.. _`install(TARGETS)`:
.. _TARGETS:
.. code-block:: cmake
@@ -147,13 +148,13 @@ project. There are several kinds of target files that may be installed:
property are treated as ``FRAMEWORK`` targets on macOS.
``BUNDLE``
- Executables marked with the ``MACOSX_BUNDLE`` property are treated as
+ Executables marked with the :prop_tgt:`MACOSX_BUNDLE` property are treated as
``BUNDLE`` targets on macOS.
``PUBLIC_HEADER``
- Any ``PUBLIC_HEADER`` files associated with a library are installed in
+ Any :prop_tgt:`PUBLIC_HEADER` files associated with a library are installed in
the destination specified by the ``PUBLIC_HEADER`` argument on non-Apple
- platforms. Rules defined by this argument are ignored for ``FRAMEWORK``
+ platforms. Rules defined by this argument are ignored for :prop_tgt:`FRAMEWORK`
libraries on Apple platforms because the associated files are installed
into the appropriate locations inside the framework folder. See
:prop_tgt:`PUBLIC_HEADER` for details.
@@ -288,18 +289,20 @@ the following additional arguments:
is not recommended to use ``NAMELINK_SKIP`` in conjunction with
``NAMELINK_COMPONENT``.
-The ``install(TARGETS)`` command can also accept the following options at the
+The `install(TARGETS)`_ command can also accept the following options at the
top level:
``EXPORT``
This option associates the installed target files with an export called
``<export-name>``. It must appear before any target options. To actually
- install the export file itself, call ``install(EXPORT)``, documented below.
+ install the export file itself, call `install(EXPORT)`_, documented below.
+ See documentation of the :prop_tgt:`EXPORT_NAME` target property to change
+ the name of the exported target.
``INCLUDES DESTINATION``
This option specifies a list of directories which will be added to the
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property of the
- ``<targets>`` when exported by the :command:`install(EXPORT)` command. If a
+ ``<targets>`` when exported by the `install(EXPORT)`_ command. If a
relative path is specified, it is treated as relative to the
``$<INSTALL_PREFIX>``.
@@ -333,7 +336,7 @@ 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.
-:command:`install(TARGETS)` can install targets that were created in
+`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
@@ -348,6 +351,8 @@ use "generator expressions" with the syntax ``$<...>``. See the
Installing Files
^^^^^^^^^^^^^^^^
+.. _`install(FILES)`:
+.. _`install(PROGRAMS)`:
.. _FILES:
.. _PROGRAMS:
@@ -436,6 +441,7 @@ use "generator expressions" with the syntax ``$<...>``. See the
Installing Directories
^^^^^^^^^^^^^^^^^^^^^^
+.. _`install(DIRECTORY)`:
.. _DIRECTORY:
.. code-block:: cmake
@@ -560,6 +566,8 @@ manual for available expressions.
Custom Installation Logic
^^^^^^^^^^^^^^^^^^^^^^^^^
+.. _`install(CODE)`:
+.. _`install(SCRIPT)`:
.. _CODE:
.. _SCRIPT:
@@ -589,6 +597,7 @@ name, not the file's contents). See the
Installing Exports
^^^^^^^^^^^^^^^^^^
+.. _`install(EXPORT)`:
.. _EXPORT:
.. code-block:: cmake
@@ -605,7 +614,7 @@ Installing Exports
The ``EXPORT`` form generates and installs a CMake file containing code to
import targets from the installation tree into another project.
Target installations are associated with the export ``<export-name>``
-using the ``EXPORT`` option of the ``install(TARGETS)`` signature
+using the ``EXPORT`` option of the `install(TARGETS)`_ signature
documented above. The ``NAMESPACE`` option will prepend ``<namespace>`` to
the target names as they are written to the import file. By default
the generated file will be called ``<export-name>.cmake`` but the ``FILE``
@@ -651,9 +660,9 @@ and installed by the current project. For example, the code
install(TARGETS myexe EXPORT myproj DESTINATION bin)
install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)
- install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules)
+ install(EXPORT_ANDROID_MK myproj DESTINATION share/ndk-modules)
-will install the executable myexe to ``<prefix>/bin`` and code to import
+will install the executable ``myexe`` to ``<prefix>/bin`` and code to import
it in the file ``<prefix>/lib/myproj/myproj.cmake`` and
``<prefix>/share/ndk-modules/Android.mk``. An outside project
may load this file with the include command and reference the ``myexe``
diff --git a/Help/command/install_files.rst b/Help/command/install_files.rst
index f5fb46d22..ff074a8a7 100644
--- a/Help/command/install_files.rst
+++ b/Help/command/install_files.rst
@@ -21,7 +21,7 @@ or its corresponding location in the binary tree may be listed. If a
file specified already has an extension, that extension will be
removed first. This is useful for providing lists of source files
such as foo.cxx when you want the corresponding foo.h to be installed.
-A typical extension is '.h'.
+A typical extension is ``.h``.
::
diff --git a/Help/command/list.rst b/Help/command/list.rst
index bfcdf34cd..39e7e2a69 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -21,6 +21,9 @@ Synopsis
list(`APPEND`_ <list> [<element>...])
list(`FILTER`_ <list> {INCLUDE | EXCLUDE} REGEX <regex>)
list(`INSERT`_ <list> <index> [<element>...])
+ list(`POP_BACK`_ <list> [<out-var>...])
+ list(`POP_FRONT`_ <list> [<out-var>...])
+ list(`PREPEND`_ <list> [<element>...])
list(`REMOVE_ITEM`_ <list> <value>...)
list(`REMOVE_AT`_ <list> <index>...)
list(`REMOVE_DUPLICATES`_ <list>)
@@ -33,8 +36,9 @@ Synopsis
Introduction
^^^^^^^^^^^^
-The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``,
-``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create
+The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``PREPEND``,
+``POP_BACK``, ``POP_FRONT``, ``REMOVE_AT``, ``REMOVE_ITEM``,
+``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create
new values for the list within the current CMake variable scope. Similar to
the :command:`set` command, the LIST command creates new variable values in
the current scope, even if the list itself is actually defined in a parent
@@ -142,6 +146,34 @@ For more information on regular expressions see also the
Inserts elements to the list to the specified location.
+.. _POP_BACK:
+
+.. code-block:: cmake
+
+ list(POP_BACK <list> [<out-var>...])
+
+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.
+
+.. _POP_FRONT:
+
+.. code-block:: cmake
+
+ list(POP_FRONT <list> [<out-var>...])
+
+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.
+
+.. _PREPEND:
+
+.. code-block:: cmake
+
+ list(PREPEND <list> [<element> ...])
+
+Insert elements to the 0th position in the list.
+
.. _REMOVE_ITEM:
.. code-block:: cmake
@@ -164,7 +196,8 @@ Removes items at given indices from the list.
list(REMOVE_DUPLICATES <list>)
-Removes duplicated items in the list.
+Removes duplicated items in the list. The relative order of items is preserved,
+but if duplicates are encountered, only the first instance is preserved.
.. _TRANSFORM:
@@ -174,84 +207,81 @@ Removes duplicated items in the list.
[OUTPUT_VARIABLE <output variable>])
Transforms the list by applying an action to all or, by specifying a
-``<SELECTOR>``, to the selected elements of the list, storing result in-place
-or in the specified output variable.
+``<SELECTOR>``, to the selected elements of the list, storing the result
+in-place or in the specified output variable.
.. note::
- ``TRANSFORM`` sub-command does not change the number of elements of the
+ The ``TRANSFORM`` sub-command does not change the number of elements in the
list. If a ``<SELECTOR>`` is specified, only some elements will be changed,
- the other ones will remain same as before the transformation.
-
-``<ACTION>`` specify the action to apply to the elements of list.
-The actions have exactly the same semantics as sub-commands of
-:command:`string` command.
+ the other ones will remain the same as before the transformation.
-The ``<ACTION>`` may be one of:
+``<ACTION>`` specifies the action to apply to the elements of the list.
+The actions have exactly the same semantics as sub-commands of the
+:command:`string` command. ``<ACTION>`` must be one of the following:
``APPEND``, ``PREPEND``: Append, prepend specified value to each element of
the list.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
+ list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
``TOUPPER``, ``TOLOWER``: Convert each element of the list to upper, lower
characters.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
+ list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
``STRIP``: Remove leading and trailing spaces from each element of the
list.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> STRIP ...)
+ list(TRANSFORM <list> STRIP ...)
``GENEX_STRIP``: Strip any
:manual:`generator expressions <cmake-generator-expressions(7)>` from each
element of the list.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> GENEX_STRIP ...)
+ list(TRANSFORM <list> GENEX_STRIP ...)
``REPLACE``: Match the regular expression as many times as possible and
substitute the replacement expression for the match for each element
of the list
(Same semantic as ``REGEX REPLACE`` from :command:`string` command).
-.. code-block:: cmake
-
- list(TRANSFORM <list> REPLACE <regular_expression>
- <replace_expression> ...)
+ .. code-block:: cmake
-``<SELECTOR>`` select which elements of the list will be transformed. Only one
-type of selector can be specified at a time.
+ list(TRANSFORM <list> REPLACE <regular_expression>
+ <replace_expression> ...)
-The ``<SELECTOR>`` may be one of:
+``<SELECTOR>`` determines which elements of the list will be transformed.
+Only one type of selector can be specified at a time. When given,
+``<SELECTOR>`` must be one of the following:
``AT``: Specify a list of indexes.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
+ list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
``FOR``: Specify a range with, optionally, an increment used to iterate over
the range.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
+ list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
``REGEX``: Specify a regular expression. Only elements matching the regular
expression will be transformed.
-.. code-block:: cmake
+ .. code-block:: cmake
- list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)
+ list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)
Ordering
diff --git a/Help/command/math.rst b/Help/command/math.rst
index 4fa55f66c..3cbe719e5 100644
--- a/Help/command/math.rst
+++ b/Help/command/math.rst
@@ -16,7 +16,7 @@ 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.
+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
diff --git a/Help/command/message.rst b/Help/command/message.rst
index 2b4b1aa0d..5dca6b417 100644
--- a/Help/command/message.rst
+++ b/Help/command/message.rst
@@ -9,24 +9,56 @@ Display a message to the user.
The optional ``<mode>`` keyword determines the type of message:
-::
-
- (none) = Important information
- STATUS = Incidental information
- WARNING = CMake Warning, continue processing
- AUTHOR_WARNING = CMake Warning (dev), continue processing
- SEND_ERROR = CMake Error, continue processing,
- but skip generation
- FATAL_ERROR = CMake Error, stop processing and generation
- DEPRECATION = CMake Deprecation Error or Warning if variable
- CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED
- is enabled, respectively, else no message.
-
-The CMake command-line tool displays STATUS messages on stdout and all
-other message types on stderr. The CMake GUI displays all messages in
-its log area. The interactive dialogs (ccmake and CMakeSetup) show
-STATUS messages one at a time on a status line and other messages in
-interactive pop-up boxes.
+``FATAL_ERROR``
+ CMake Error, stop processing and generation.
+
+``SEND_ERROR``
+ CMake Error, continue processing, but skip generation.
+
+``WARNING``
+ CMake Warning, continue processing.
+
+``AUTHOR_WARNING``
+ CMake Warning (dev), continue processing.
+
+``DEPRECATION``
+ CMake Deprecation Error or Warning if variable
+ :variable:`CMAKE_ERROR_DEPRECATED` or :variable:`CMAKE_WARN_DEPRECATED`
+ is enabled, respectively, else no message.
+
+(none) or ``NOTICE``
+ Important message printed to stderr to attract user's attention.
+
+``STATUS``
+ The main interesting messages that project users might be interested in.
+ Ideally these should be concise, no more than a single line, but still
+ informative.
+
+``VERBOSE``
+ Detailed informational messages intended for project users. These messages
+ should provide additional details that won't be of interest in most cases,
+ but which may be useful to those building the project when they want deeper
+ insight into what's happening.
+
+``DEBUG``
+ Detailed informational messages intended for developers working on the
+ project itself as opposed to users who just want to build it. These messages
+ will not typically be of interest to other users building the project and
+ will often be closely related to internal implementation details.
+
+``TRACE``
+ Fine-grained messages with very low-level implementation details. Messages
+ using this log level would normally only be temporary and would expect to be
+ removed before releasing the project, packaging up the files, etc.
+
+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
+:manual:`CMake GUI <cmake-gui(1)>` displays all messages in its log area.
+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 ``--loglevel`` command-line option to each of
+these tools can be used to control which messages will be shown.
CMake Warning and Error message text displays using a simple markup
language. Non-indented text is formatted in line-wrapped paragraphs
diff --git a/Help/command/output_required_files.rst b/Help/command/output_required_files.rst
index 8bc6a730e..b3a6e8653 100644
--- a/Help/command/output_required_files.rst
+++ b/Help/command/output_required_files.rst
@@ -14,6 +14,6 @@ more advanced scanner.
output_required_files(srcfile outputfile)
Outputs a list of all the source files that are required by the
-specified srcfile. This list is written into outputfile. This is
-similar to writing out the dependencies for srcfile except that it
-jumps from .h files into .cxx, .c and .cpp files if possible.
+specified ``srcfile``. This list is written into ``outputfile``. This is
+similar to writing out the dependencies for ``srcfile`` except that it
+jumps from ``.h`` files into ``.cxx``, ``.c`` and ``.cpp`` files if possible.
diff --git a/Help/command/project.rst b/Help/command/project.rst
index 688e56c3f..baf18be64 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -31,10 +31,6 @@ Further variables are set by the optional arguments described in the following.
If any of these arguments is not used, then the corresponding variables are
set to the empty string.
-If the variable :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` exists,
-the file pointed to by that variable will be included as the last step of the
-project command.
-
Options
^^^^^^^
@@ -59,7 +55,7 @@ The options are:
* :variable:`PROJECT_VERSION_TWEAK`,
:variable:`<PROJECT-NAME>_VERSION_TWEAK`.
- When the :command:`project()` command is called from the top-level ``CMakeLists.txt``,
+ 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>``
@@ -72,7 +68,7 @@ The options are:
It is recommended that this description is a relatively short string,
usually no more than a few words.
- When the :command:`project()` command is called from the top-level ``CMakeLists.txt``,
+ 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`.
``HOMEPAGE_URL <url-string>``
@@ -83,7 +79,7 @@ The options are:
to ``<url-string>``, which should be the canonical home URL for the project.
- When the :command:`project()` command is called from the top-level ``CMakeLists.txt``,
+ When the ``project()`` command is called from the top-level ``CMakeLists.txt``,
then the URL also is stored in the variable :variable:`CMAKE_PROJECT_HOMEPAGE_URL`.
``LANGUAGES <language-name>...``
@@ -102,18 +98,32 @@ The options are:
The variables set through the ``VERSION``, ``DESCRIPTION`` and ``HOMEPAGE_URL``
options are intended for use as default values in package metadata and documentation.
+Code Injection
+^^^^^^^^^^^^^^
+
+If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variable is set, the file
+pointed to by that variable will be included as the first step of the
+``project()`` command.
+
+If the :variable:`CMAKE_PROJECT_INCLUDE` or
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` variables are set, the files
+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`.
+
Usage
^^^^^
The top-level ``CMakeLists.txt`` file for a project must contain a
-literal, direct call to the :command:`project` command; loading one
+literal, direct call to the ``project()`` command; loading one
through the :command:`include` command is not sufficient. If no such
-call exists CMake will implicitly add one to the top that enables the
-default languages (``C`` and ``CXX``).
+call exists, CMake will issue a warning and pretend there is a
+``project(Project)`` at the top to enable the default languages
+(``C`` and ``CXX``).
.. note::
- Call the :command:`cmake_minimum_required` command at the beginning
- of the top-level ``CMakeLists.txt`` file even before calling the
- :command:`project()` command. It is important to establish version and
- policy settings before invoking other commands whose behavior they
- may affect. See also policy :policy:`CMP0000`.
+ Call the ``project()`` command near the top of the top-level
+ ``CMakeLists.txt``, but *after* calling :command:`cmake_minimum_required`.
+ It is important to establish version and policy settings before invoking
+ other commands whose behavior they may affect.
+ See also policy :policy:`CMP0000`.
diff --git a/Help/command/set_property.rst b/Help/command/set_property.rst
index 2624b4bc8..ec08c8f99 100644
--- a/Help/command/set_property.rst
+++ b/Help/command/set_property.rst
@@ -35,7 +35,7 @@ It must be one of the following:
``SOURCE``
Scope may name zero or more source files. Note that source
file properties are visible only to targets added in the same
- directory (CMakeLists.txt).
+ directory (``CMakeLists.txt``).
See also the :command:`set_source_files_properties` command.
``INSTALL``
@@ -48,7 +48,7 @@ It must be one of the following:
Path components have to be separated by forward slashes,
must be normalized and are case sensitive.
- To reference the installation prefix itself with a relative path use ".".
+ To reference the installation prefix itself with a relative path use ``.``.
Currently installed file properties are only defined for
the WIX generator where the given paths are relative
diff --git a/Help/command/set_source_files_properties.rst b/Help/command/set_source_files_properties.rst
index 91f995ce5..ab95d7094 100644
--- a/Help/command/set_source_files_properties.rst
+++ b/Help/command/set_source_files_properties.rst
@@ -16,4 +16,4 @@ See also the :command:`set_property(SOURCE)` command.
See :ref:`Source File Properties` for the list of properties known
to CMake. Source file properties are visible only to targets added
-in the same directory (CMakeLists.txt).
+in the same directory (``CMakeLists.txt``).
diff --git a/Help/command/string.rst b/Help/command/string.rst
index 893fb4324..2e89d7b9e 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -28,6 +28,7 @@ Synopsis
string(`SUBSTRING`_ <string> <begin> <length> <out-var>)
string(`STRIP`_ <string> <out-var>)
string(`GENEX_STRIP`_ <string> <out-var>)
+ string(`REPEAT`_ <string> <count> <out-var>)
`Comparison`_
string(`COMPARE`_ <op> <string1> <string2> <out-var>)
@@ -269,6 +270,14 @@ trailing spaces removed.
Strip any :manual:`generator expressions <cmake-generator-expressions(7)>`
from the ``input string`` and store the result in the ``output variable``.
+.. _REPEAT:
+
+.. code-block:: cmake
+
+ string(REPEAT <input string> <count> <output variable>)
+
+Produce the output string as repetion of ``input string`` ``count`` times.
+
Comparison
^^^^^^^^^^
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index c5e4f9fcf..c2e7e8ac9 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -57,7 +57,7 @@ Each ``<item>`` may be:
as when a shared library is detected to have no ``SONAME`` field.
See policy :policy:`CMP0060` for discussion of another case.
- If the library file is in a Mac OSX framework, the ``Headers`` directory
+ If the library file is in a macOS framework, the ``Headers`` directory
of the framework will also be processed as a
:ref:`usage requirement <Target Usage Requirements>`. This has the same
effect as passing the framework directory as an include directory.
diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst
index 285455a81..b5abbc476 100644
--- a/Help/command/target_link_options.rst
+++ b/Help/command/target_link_options.rst
@@ -1,7 +1,8 @@
target_link_options
-------------------
-Add link options to a target.
+Add options to the link step for an executable, shared library or module
+library target.
.. code-block:: cmake
@@ -9,20 +10,25 @@ Add link options to a target.
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
-Specifies link options to use when linking a given target. The
-named ``<target>`` must have been created by a command such as
+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>`.
+This command can be used to add any link options, but alternative commands
+exist to add libraries (:command:`target_link_libraries` or
+:command:`link_libraries`). See documentation of the
+:prop_dir:`directory <LINK_OPTIONS>` and
+:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
+
+.. note::
+
+ This command cannot be used to add options for static library targets,
+ since they do not use a linker. To add archiver or MSVC librarian flags,
+ see the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+
If ``BEFORE`` is specified, the content will be prepended to the property
instead of being appended.
-This command can be used to add any options, but
-alternative commands exist to add libraries
-(:command:`target_link_libraries` and :command:`link_libraries`).
-See documentation of the :prop_dir:`directory <LINK_OPTIONS>` and
-:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
-
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:`LINK_OPTIONS` property of
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index ca8fc77fa..0bc2ca37a 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -135,6 +135,7 @@ default values:
* :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
diff --git a/Help/command/use_mangled_mesa.rst b/Help/command/use_mangled_mesa.rst
index 4d9e12b3e..5b0e2ee06 100644
--- a/Help/command/use_mangled_mesa.rst
+++ b/Help/command/use_mangled_mesa.rst
@@ -9,7 +9,7 @@ Copy mesa headers for use in combination with system GL.
use_mangled_mesa(PATH_TO_MESA OUTPUT_DIRECTORY)
-The path to mesa includes, should contain gl_mangle.h. The mesa
+The path to mesa includes, should contain ``gl_mangle.h``. The mesa
headers are copied to the specified output directory. This allows
mangled mesa headers to override other GL headers by being added to
the include directory path earlier.
diff --git a/Help/command/variable_requires.rst b/Help/command/variable_requires.rst
index b4742a523..322b15459 100644
--- a/Help/command/variable_requires.rst
+++ b/Help/command/variable_requires.rst
@@ -18,5 +18,5 @@ tested, if that variable is false nothing else is done. If
``TEST_VARIABLE`` is true, then the next argument (``RESULT_VARIABLE``)
is a variable that is set to true if all the required variables are set.
The rest of the arguments are variables that must be true or not set
-to NOTFOUND to avoid an error. If any are not true, an error is
+to ``NOTFOUND`` to avoid an error. If any are not true, an error is
reported.
diff --git a/Help/cpack_gen/bundle.rst b/Help/cpack_gen/bundle.rst
index 29727e2e9..b16dbda03 100644
--- a/Help/cpack_gen/bundle.rst
+++ b/Help/cpack_gen/bundle.rst
@@ -12,26 +12,27 @@ Bundle-specific parameters (``CPACK_BUNDLE_xxx``).
.. variable:: CPACK_BUNDLE_NAME
- The name of the generated bundle. This appears in the OSX finder as the
+ The name of the generated bundle. This appears in the macOS Finder as the
bundle name. Required.
.. variable:: CPACK_BUNDLE_PLIST
- Path to an OSX plist file that will be used for the generated bundle. This
- assumes that the caller has generated or specified their own Info.plist
+ Path to an macOS Property List (``.plist``) file that will be used
+ for the generated bundle. This
+ assumes that the caller has generated or specified their own ``Info.plist``
file. Required.
.. variable:: CPACK_BUNDLE_ICON
- Path to an OSX icon file that will be used as the icon for the generated
- bundle. This is the icon that appears in the OSX finder for the bundle, and
- in the OSX dock when the bundle is opened. Required.
+ Path to an macOS icon file that will be used as the icon for the generated
+ bundle. This is the icon that appears in the macOS Finder for the bundle, and
+ in the macOS dock when the bundle is opened. Required.
.. variable:: CPACK_BUNDLE_STARTUP_COMMAND
Path to a startup script. This is a path to an executable or script that
will be run whenever an end-user double-clicks the generated bundle in the
- OSX Finder. Optional.
+ macOS Finder. Optional.
.. variable:: CPACK_BUNDLE_APPLE_CERT_APP
@@ -42,8 +43,9 @@ Bundle-specific parameters (``CPACK_BUNDLE_xxx``).
.. variable:: CPACK_BUNDLE_APPLE_ENTITLEMENTS
- The name of the ``Plist`` file that contains your apple entitlements for sandboxing
- your application. This file is required for submission to the Mac App Store.
+ 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
diff --git a/Help/cpack_gen/external.rst b/Help/cpack_gen/external.rst
index e4912a462..406f6be1a 100644
--- a/Help/cpack_gen/external.rst
+++ b/Help/cpack_gen/external.rst
@@ -13,7 +13,7 @@ provided by CPack, such as component installation and the dependency graph.
Integration with External Packaging Tools
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The CPack External generator generates a .json file containing the
+The CPack External generator generates a ``.json`` file containing the
CPack internal metadata, which gives external software information
on how to package the software. External packaging software may itself
invoke CPack, consume the generated metadata,
diff --git a/Help/cpack_gen/ifw.rst b/Help/cpack_gen/ifw.rst
index e43b1d646..feccd3db0 100644
--- a/Help/cpack_gen/ifw.rst
+++ b/Help/cpack_gen/ifw.rst
@@ -135,6 +135,10 @@ Package
Wizard style to be used ("Modern", "Mac", "Aero" or "Classic").
+.. variable:: CPACK_IFW_PACKAGE_STYLE_SHEET
+
+ Filename for a stylesheet.
+
.. variable:: CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH
Default width of the wizard in pixels. Setting a banner image will override this.
diff --git a/Help/cpack_gen/nsis.rst b/Help/cpack_gen/nsis.rst
index 9f82a04bd..cd2aea682 100644
--- a/Help/cpack_gen/nsis.rst
+++ b/Help/cpack_gen/nsis.rst
@@ -1,19 +1,19 @@
CPack NSIS Generator
--------------------
-CPack NSIS generator specific options
+CPack Nullsoft Scriptable Install System (NSIS) generator specific options
Variables specific to CPack NSIS generator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following variables are specific to the graphical installers built
-on Windows using the Nullsoft Installation System.
+on Windows Nullsoft Scriptable Install System.
.. variable:: CPACK_NSIS_INSTALL_ROOT
The default installation directory presented to the end user by the NSIS
installer is under this root dir. The full directory presented to the end
- user is: ${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}
+ user is: ``${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}``
.. variable:: CPACK_NSIS_MUI_ICON
@@ -31,11 +31,11 @@ on Windows using the Nullsoft Installation System.
.. variable:: CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
- The filename of a bitmap to use as the NSIS MUI_WELCOMEFINISHPAGE_BITMAP.
+ The filename of a bitmap to use as the NSIS ``MUI_WELCOMEFINISHPAGE_BITMAP``.
.. variable:: CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
- The filename of a bitmap to use as the NSIS MUI_UNWELCOMEFINISHPAGE_BITMAP.
+ The filename of a bitmap to use as the NSIS ``MUI_UNWELCOMEFINISHPAGE_BITMAP``.
.. variable:: CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS
@@ -54,25 +54,25 @@ on Windows using the Nullsoft Installation System.
.. variable:: CPACK_NSIS_COMPRESSOR
- The arguments that will be passed to the NSIS SetCompressor command.
+ The arguments that will be passed to the NSIS `SetCompressor` command.
.. variable:: CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL
- Ask about uninstalling previous versions first. If this is set to "ON",
+ Ask about uninstalling previous versions first. If this is set to ``ON``,
then an installer will look for previous installed versions and if one is
found, ask the user whether to uninstall it before proceeding with the
install.
.. variable:: CPACK_NSIS_MODIFY_PATH
- Modify PATH toggle. If this is set to "ON", then an extra page will appear
+ Modify ``PATH`` toggle. If this is set to ``ON``, then an extra page will appear
in the installer that will allow the user to choose whether the program
- directory should be added to the system PATH variable.
+ directory should be added to the system ``PATH`` variable.
.. variable:: CPACK_NSIS_DISPLAY_NAME
- The display name string that appears in the Windows Add/Remove Program
- control panel
+ The display name string that appears in the Windows `Apps & features`
+ in `Control Panel`
.. variable:: CPACK_NSIS_PACKAGE_NAME
@@ -97,21 +97,21 @@ on Windows using the Nullsoft Installation System.
.. variable:: CPACK_NSIS_<compName>_INSTALL_DIRECTORY
- Custom install directory for the specified component <compName> instead
- of $INSTDIR.
+ Custom install directory for the specified component ``<compName>`` instead
+ of ``$INSTDIR``.
.. variable:: CPACK_NSIS_CREATE_ICONS_EXTRA
- Additional NSIS commands for creating start menu shortcuts.
+ Additional NSIS commands for creating `Start Menu` shortcuts.
.. variable:: CPACK_NSIS_DELETE_ICONS_EXTRA
- Additional NSIS commands to uninstall start menu shortcuts.
+ Additional NSIS commands to uninstall `Start Menu` shortcuts.
.. variable:: CPACK_NSIS_EXECUTABLES_DIRECTORY
- Creating NSIS start menu links assumes that they are in 'bin' unless this
- variable is set. For example, you would set this to 'exec' if your
+ Creating NSIS `Start Menu` links assumes that they are in ``bin`` unless this
+ variable is set. For example, you would set this to ``exec`` if your
executables are in an exec directory.
.. variable:: CPACK_NSIS_MUI_FINISHPAGE_RUN
@@ -121,8 +121,8 @@ on Windows using the Nullsoft Installation System.
.. variable:: CPACK_NSIS_MENU_LINKS
- Specify links in [application] menu. This should contain a list of pair
- "link" "link name". The link may be a URL or a path relative to
+ Specify links in ``[application]`` menu. This should contain a list of pair
+ ``link`` ``link name``. The link may be a URL or a path relative to
installation prefix. Like::
set(CPACK_NSIS_MENU_LINKS
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index 65009db84..2693c7b62 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -22,19 +22,19 @@ http://www.rpm.org/wiki/Docs
.. note::
- `<COMPONENT>` part of variables is preferred to be in upper case (for e.g. if
- component is named `foo` then use `CPACK_RPM_FOO_XXXX` variable name format)
- as is with other `CPACK_<COMPONENT>_XXXX` variables.
+ `<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)
+ as is with other ``CPACK_<COMPONENT>_XXXX`` variables.
For the purposes of back compatibility (CMake/CPack version 3.5 and lower)
- support for same cased component (e.g. `fOo` would be used as
- `CPACK_RPM_fOo_XXXX`) is still supported for variables defined in older
+ support for same cased component (e.g. ``fOo`` would be used as
+ ``CPACK_RPM_fOo_XXXX``) is still supported for variables defined in older
versions of CMake/CPack but is not guaranteed for variables that
will be added in the future. For the sake of back compatibility same cased
component variables also override upper cased versions where both are
present.
-Here are some CPack RPM generator wiki resources that are here for historic reasons and
-are no longer maintained but may still prove useful:
+Here are some CPack RPM generator wiki resources that are here for historic
+reasons and are no longer maintained but may still prove useful:
- https://gitlab.kitware.com/cmake/community/wikis/doc/cpack/Configuration
- https://gitlab.kitware.com/cmake/community/wikis/doc/cpack/PackageGenerators#rpm-unix-only
@@ -48,8 +48,8 @@ List of CPack RPM generator specific variables:
* Mandatory : NO
* Default : OFF
- If enabled (ON) multiple packages are generated. By default a single package
- containing files of all components is generated.
+ If enabled (``ON``) multiple packages are generated. By default
+ a single package containing files of all components is generated.
.. variable:: CPACK_RPM_PACKAGE_SUMMARY
CPACK_RPM_<component>_PACKAGE_SUMMARY
@@ -76,14 +76,14 @@ List of CPack RPM generator specific variables:
* Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
replaced by '-'
- This may be set to ``RPM-DEFAULT`` to allow rpmbuild tool to generate package
+ This may be set to ``RPM-DEFAULT`` to allow ``rpmbuild`` tool to generate package
file name by itself.
Alternatively provided package file name must end with ``.rpm`` suffix.
.. note::
By using user provided spec file, rpm macro extensions such as for
- generating debuginfo packages or by simply using multiple components more
+ generating ``debuginfo`` packages or by simply using multiple components more
than one rpm file may be generated, either from a single spec file or from
multiple spec files (each component execution produces its own spec file).
In such cases duplicate file names may occur as a result of this variable
@@ -127,7 +127,7 @@ List of CPack RPM generator specific variables:
* Mandatory : YES
* Default : Native architecture output by ``uname -m``
- This may be set to ``noarch`` if you know you are building a noarch package.
+ This may be set to ``noarch`` if you know you are building a ``noarch`` package.
.. variable:: CPACK_RPM_PACKAGE_RELEASE
@@ -207,7 +207,7 @@ List of CPack RPM generator specific variables:
* Default : -
May be used to override RPM compression type to be used to build the
- RPM. For example some Linux distribution now default to lzma or xz
+ RPM. For example some Linux distribution now default to ``lzma`` or ``xz``
compression whereas older cannot use such RPM. Using this one can enforce
compression type to be used.
@@ -226,8 +226,8 @@ List of CPack RPM generator specific variables:
* Mandatory : NO
* Default : -
- May be used to enable (1, yes) or disable (0, no) automatic shared libraries
- dependency detection. Dependencies are added to requires list.
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``) automatic
+ shared libraries dependency detection. Dependencies are added to requires list.
.. note::
@@ -241,9 +241,9 @@ List of CPack RPM generator specific variables:
* Mandatory : NO
* Default : -
- May be used to enable (1, yes) or disable (0, no) automatic listing of shared
- libraries that are provided by the package. Shared libraries are added to
- provides list.
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``)
+ automatic listing of shared libraries that are provided by the package.
+ Shared libraries are added to provides list.
.. note::
@@ -258,8 +258,8 @@ List of CPack RPM generator specific variables:
* Default : -
Variable enables/disables autoreq and autoprov at the same time.
- See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and :variable:`CPACK_RPM_PACKAGE_AUTOPROV`
- for more details.
+ See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and
+ :variable:`CPACK_RPM_PACKAGE_AUTOPROV` for more details.
.. note::
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index a8942cd7c..1153a095f 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -188,12 +188,6 @@ Update ``Source/CMakeVersion.cmake`` to set the version to
set(CMake_VERSION_PATCH 0)
set(CMake_VERSION_RC 1)
-Update ``Utilities/Release/upload_release.cmake``:
-
-.. code-block:: cmake
-
- set(VERSION $ver)
-
Update uses of ``DEVEL_CMAKE_VERSION`` in the source tree to mention the
actual version number:
diff --git a/Help/dev/review.rst b/Help/dev/review.rst
index 1d664c4b8..cbde6feea 100644
--- a/Help/dev/review.rst
+++ b/Help/dev/review.rst
@@ -377,7 +377,15 @@ command is needed to stage it again.
Resolve
=======
-A MR may be resolved in one of the following ways.
+The workflow used by the CMake project supports a number of different
+ways in which a MR can be moved to a resolved state. In addition to
+the conventional practices of merging or closing a MR without merging it,
+a MR can also be moved to a quasi-resolved state pending some action.
+This may involve moving discussion to an issue or it may be the result of
+an extended period of inactivity. These quasi-resolved states are used
+to help manage the relatively large number of MRs the project receives
+and are not an indication of the changes being rejected. The following
+sections explain the different resolutions a MR may be given.
Merge
-----
@@ -433,15 +441,68 @@ Close
-----
If review has concluded that the MR should not be integrated then it
-may be closed through GitLab.
+may be closed through GitLab. This would normally be a final state
+with no expectation that the MR would be re-opened in the future.
+It is also used when a MR is being superseded by another separate one,
+in which case a reference to the new MR should be added to the MR being
+closed.
Expire
------
If progress on a MR has stalled for a while, it may be closed with a
``workflow:expired`` label and a comment indicating that the MR has
-been closed due to inactivity.
-
-Contributors are welcome to re-open an expired MR when they are ready
-to continue work. Please re-open *before* pushing an update to the
-MR topic branch to ensure GitLab will still act on the association.
+been closed due to inactivity (it may also be done where the MR is blocked
+for an extended period by work in a different MR). This is not an
+indication that there is a problem with the MR's content, it is only a
+practical measure to allow the reviewers to focus attention on MRs that
+are actively being worked on. As a guide, the average period of inactivity
+before transitioning a MR to the expired state would be around 2 weeks,
+but this may decrease to 1 week or less when there is a high number of
+open merge requests.
+
+Reviewers would usually provide a message similar to the following when
+resolving a MR as expired::
+
+ Closing for now. @<MR-author> please re-open when ready to continue work.
+
+This is to make it clear to contributors that they are welcome to re-open
+the expired MR when they are ready to return to working on it and moving
+it forward. In the meantime, the MR will appear as ``Closed`` in GitLab,
+but it can be differentiated from permanently closed MRs by the presence
+of the ``workflow:expired`` label.
+
+**NOTE:** Please re-open *before* pushing an update to the MR topic branch
+to ensure GitLab will still act on the association. If changes are pushed
+before re-opening the MR, the reviewer should initiate a ``Do: check`` to
+force GitLab to act on the updates.
+
+External Discussion
+-------------------
+
+In some situations, a series of comments on a MR may develop into a more
+involved discussion, or it may become apparent that there are broader
+discussions that need to take place before the MR can move forward in an
+agreed direction. Such discussions are better suited to GitLab issues
+rather than in a MR because MRs may be superseded by a different MR, or
+the set of changes may evolve to look quite different to the context in
+which the discussions began. When this occurs, reviewers may ask the
+MR author to open an issue to discuss things there and they will transition
+the MR to a resolved state with the label ``workflow:external-discussion``.
+The MR will appear in GitLab as closed, but it can be differentiated from
+permanently closed MRs by the presence of the ``workflow:external-discussion``
+label. Reviewers should leave a message clearly explaining the action
+so that the MR author understands that the MR closure is temporary and
+it is clear what actions need to happen next. The following is an example
+of such a message, but it will usually be necessary to tailor the message
+to the individual situation::
+
+ The desired behavior here looks to be more involved than first thought.
+ Please open an issue so we can discuss the relevant details there.
+ Once the path forward is clear, we can re-open this MR and continue work.
+
+When the discussion in the associated issue runs its course and the way
+forward is clear, the MR can be re-opened again and the
+``workflow:external-discussion`` label removed. Reviewers should ensure
+that the issue created contains a reference to the MR so that GitLab
+provides a cross-reference to link the two.
diff --git a/Help/envvar/ASM_DIALECT.rst b/Help/envvar/ASM_DIALECT.rst
index cabb95971..a06e3cba2 100644
--- a/Help/envvar/ASM_DIALECT.rst
+++ b/Help/envvar/ASM_DIALECT.rst
@@ -4,8 +4,9 @@ ASM<DIALECT>
.. include:: ENV_VAR.txt
Preferred executable for compiling a specific dialect of assembly language
-files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM``, ``ASM_MASM`` or
-``ASM-ATT``. Will only be used by CMake on the first configuration to determine
+files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM`` (Netwide Assembler),
+``ASM_MASM`` (Microsoft Assembler) or ``ASM-ATT`` (Assembler AT&T).
+Will only be used by CMake on the first configuration to determine
``ASM<DIALECT>`` compiler, after which the value for ``ASM<DIALECT>`` is stored
in the cache as
:variable:`CMAKE_ASM<DIALECT>_COMPILER <CMAKE_<LANG>_COMPILER>`. For subsequent
diff --git a/Help/envvar/ASM_DIALECTFLAGS.rst b/Help/envvar/ASM_DIALECTFLAGS.rst
index 90cbbdb39..3c3b02a76 100644
--- a/Help/envvar/ASM_DIALECTFLAGS.rst
+++ b/Help/envvar/ASM_DIALECTFLAGS.rst
@@ -6,8 +6,8 @@ ASM<DIALECT>FLAGS
Default compilation flags to be used when compiling a specific dialect of an
assembly language. ``ASM<DIALECT>FLAGS`` can be ``ASMFLAGS``, ``ASM_NASMFLAGS``,
``ASM_MASMFLAGS`` or ``ASM-ATTFLAGS``. Will only be used by CMake on the
-first configuration to determine ``ASM<DIALECT>`` default compilation flags, after
-which the value for ``ASM<DIALECT>FLAGS`` is stored in the cache as
-:variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
-run (including the first), the environment variable will be ignored if the
-:variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+first configuration to determine ``ASM_<DIALECT>`` default compilation
+flags, after which the value for ``ASM<DIALECT>FLAGS`` is stored in the cache
+as ``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>``. For any configuration
+run (including the first), the environment variable will be ignored, if the
+``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`` variable is defined.
diff --git a/Help/envvar/CMAKE_GENERATOR.rst b/Help/envvar/CMAKE_GENERATOR.rst
new file mode 100644
index 000000000..f2d055f10
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR.rst
@@ -0,0 +1,16 @@
+CMAKE_GENERATOR
+---------------
+
+.. include:: ENV_VAR.txt
+
+Specifies the CMake default generator to use when no generator is supplied
+with ``-G``. If the provided value doesn't name a generator known by CMake,
+the internal default is used. Either way the resulting generator selection
+is stored in the :variable:`CMAKE_GENERATOR` variable.
+
+Some generators may be additionally configured using the environment
+variables:
+
+* :envvar:`CMAKE_GENERATOR_PLATFORM`
+* :envvar:`CMAKE_GENERATOR_TOOLSET`
+* :envvar:`CMAKE_GENERATOR_INSTANCE`
diff --git a/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
new file mode 100644
index 000000000..1654fa1db
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
@@ -0,0 +1,7 @@
+CMAKE_GENERATOR_INSTANCE
+------------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_INSTANCE` if no Cache entry is
+present. This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
new file mode 100644
index 000000000..917b30b14
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
@@ -0,0 +1,8 @@
+CMAKE_GENERATOR_PLATFORM
+------------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_PLATFORM` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-A`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
new file mode 100644
index 000000000..7ac3856a1
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
@@ -0,0 +1,8 @@
+CMAKE_GENERATOR_TOOLSET
+-----------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_TOOLSET` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-T`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
index b769d51d8..e1991b2df 100644
--- a/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
+++ b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
@@ -4,4 +4,4 @@ CTEST_INTERACTIVE_DEBUG_MODE
.. include:: ENV_VAR.txt
Environment variable that will exist and be set to ``1`` when a test executed
-by CTest is run in interactive mode.
+by :manual:`ctest(1)` is run in interactive mode.
diff --git a/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
index bf860cb40..d8b42624f 100644
--- a/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
+++ b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
@@ -4,6 +4,6 @@ CTEST_OUTPUT_ON_FAILURE
.. include:: ENV_VAR.txt
Boolean environment variable that controls if the output should be logged for
-failed tests. Set the value to 1, True, or ON to enable output on failure.
+failed tests. Set the value to ``1``, ``True``, or ``ON`` to enable output on failure.
See :manual:`ctest(1)` for more information on controlling output of failed
tests.
diff --git a/Help/envvar/CTEST_PROGRESS_OUTPUT.rst b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
index de23e1191..b36a6b8c2 100644
--- a/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
+++ b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
@@ -4,7 +4,7 @@ CTEST_PROGRESS_OUTPUT
.. include:: ENV_VAR.txt
Boolean environment variable that affects how :manual:`ctest <ctest(1)>`
-command output reports overall progress. When set to 1, TRUE, ON or anything
+command output reports overall progress. When set to ``1``, ``TRUE``, ``ON`` or anything
else that evaluates to boolean true, progress is reported by repeatedly
updating the same line. This greatly reduces the overall verbosity, but is
only supported when output is sent directly to a terminal. If the environment
diff --git a/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
index 2b303a4e9..6a52d6494 100644
--- a/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
+++ b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
@@ -3,5 +3,6 @@ DASHBOARD_TEST_FROM_CTEST
.. include:: ENV_VAR.txt
-Environment variable that will exist when a test executed by CTest is run
-in non-interactive mode. The value will be equal to :variable:`CMAKE_VERSION`.
+Environment variable that will exist when a test executed by :manual:`ctest(1)`
+is run in non-interactive mode. The value will be equal to
+:variable:`CMAKE_VERSION`.
diff --git a/Help/envvar/PackageName_ROOT.rst b/Help/envvar/PackageName_ROOT.rst
index ecec63bd0..82b0a069e 100644
--- a/Help/envvar/PackageName_ROOT.rst
+++ b/Help/envvar/PackageName_ROOT.rst
@@ -5,7 +5,7 @@
Calls to :command:`find_package(<PackageName>)` will search in prefixes
specified by the ``<PackageName>_ROOT`` environment variable, where
-``<PackageName>`` is the name given to the ``find_package`` call
+``<PackageName>`` is the name given to the :command:`find_package` call
and ``_ROOT`` is literal. For example, ``find_package(Foo)`` will search
prefixes specified in the ``Foo_ROOT`` environment variable (if set).
See policy :policy:`CMP0074`.
diff --git a/Help/envvar/SWIFTC.rst b/Help/envvar/SWIFTC.rst
new file mode 100644
index 000000000..b12e51df9
--- /dev/null
+++ b/Help/envvar/SWIFTC.rst
@@ -0,0 +1,11 @@
+SWIFTC
+------
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``Swift`` language files. Will only be used by
+CMake on the first configuration to determine ``Swift`` compiler, after which the
+value for ``SWIFTC`` is stored in the cache as
+:variable:`CMAKE_Swift_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration run
+(including the first), the environment variable will be ignored if the
+:variable:`CMAKE_Swift_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
diff --git a/Help/generator/CodeBlocks.rst b/Help/generator/CodeBlocks.rst
index 06cc746b1..d830542eb 100644
--- a/Help/generator/CodeBlocks.rst
+++ b/Help/generator/CodeBlocks.rst
@@ -4,14 +4,14 @@ CodeBlocks
Generates CodeBlocks project files.
Project files for CodeBlocks will be created in the top directory and
-in every subdirectory which features a CMakeLists.txt file containing
-a PROJECT() call. Additionally a hierarchy of makefiles is generated
+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 make target. A "make install" target is
+project through the default ``all`` target. An ``install`` target is
also provided.
This "extra" generator may be specified as:
diff --git a/Help/generator/CodeLite.rst b/Help/generator/CodeLite.rst
index 3e60aa6d6..46fa5bef7 100644
--- a/Help/generator/CodeLite.rst
+++ b/Help/generator/CodeLite.rst
@@ -7,11 +7,11 @@ 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 behaviour from projects to targets as the basis
+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 make target. A "make install" target is
-also provided.
+project through the default ``all`` target. An ``install`` target
+is also provided.
This "extra" generator may be specified as:
diff --git a/Help/generator/Eclipse CDT4.rst b/Help/generator/Eclipse CDT4.rst
index eb68bf094..634e2b6dd 100644
--- a/Help/generator/Eclipse CDT4.rst
+++ b/Help/generator/Eclipse CDT4.rst
@@ -7,7 +7,7 @@ Project files for Eclipse will be created in the top directory. In
out of source builds, a linked resource to the top level source
directory will be created. Additionally a hierarchy of makefiles is
generated into the build tree. The appropriate make program can build
-the project through the default make target. A "make install" target
+the project through the default ``all`` target. An ``install`` target
is also provided.
This "extra" generator may be specified as:
diff --git a/Help/generator/Green Hills MULTI.rst b/Help/generator/Green Hills MULTI.rst
index e474682b6..dffc6795d 100644
--- a/Help/generator/Green Hills MULTI.rst
+++ b/Help/generator/Green Hills MULTI.rst
@@ -9,8 +9,9 @@ via the :variable:`CMAKE_BUILD_TYPE` variable.
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.
+``<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``
@@ -33,18 +34,19 @@ Cache variables that are used for toolset and target system customization:
* ``GHS_TOOLSET_ROOT``
| Root path for ``toolset`` searches.
- | Defaults to ``C:/ghs``.
+ | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
* ``GHS_OS_ROOT``
| Root path for RTOS searches.
- | Defaults to ``C:/ghs``.
+ | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
-* ``GHS_OS_DIR``
+* ``GHS_OS_DIR`` and ``GHS_OS_DIR_OPTION``
| Sets ``-os_dir`` entry in project file.
| Defaults to latest platform OS installation at ``GHS_OS_ROOT``. Set this value if
a specific RTOS is to be used.
+ | ``GHS_OS_DIR_OPTION`` default value is ``-os_dir``.
* ``GHS_BSP_NAME``
diff --git a/Help/generator/Kate.rst b/Help/generator/Kate.rst
index 9b61a93b3..129bf631b 100644
--- a/Help/generator/Kate.rst
+++ b/Help/generator/Kate.rst
@@ -5,10 +5,10 @@ Generates Kate project files.
A project file for Kate will be created in the top directory in the top level
build directory.
-To use it in kate, the Project plugin must be enabled.
-The project file is loaded in kate simply by opening the
-ProjectName.kateproject file in the editor.
-If the kate Build-plugin is enabled, all targets generated by CMake are
+To use it in Kate, the Project plugin must be enabled.
+The project file is loaded in Kate by opening the
+``ProjectName.kateproject`` file in the editor.
+If the Kate Build-plugin is enabled, all targets generated by CMake are
available for building.
This "extra" generator may be specified as:
diff --git a/Help/generator/MSYS Makefiles.rst b/Help/generator/MSYS Makefiles.rst
index f7cfa4461..75b9fe531 100644
--- a/Help/generator/MSYS Makefiles.rst
+++ b/Help/generator/MSYS Makefiles.rst
@@ -1,7 +1,8 @@
MSYS Makefiles
--------------
-Generates makefiles for use with MSYS ``make`` under the MSYS shell.
+Generates makefiles for use with MSYS (Minimal SYStem)
+``make`` under the MSYS shell.
Use this generator in a MSYS shell prompt and using ``make`` as the build
tool. The generated makefiles use ``/bin/sh`` as the shell to launch build
diff --git a/Help/generator/MinGW Makefiles.rst b/Help/generator/MinGW Makefiles.rst
index 9fe5fe3e5..134ea7094 100644
--- a/Help/generator/MinGW Makefiles.rst
+++ b/Help/generator/MinGW Makefiles.rst
@@ -4,7 +4,8 @@ MinGW Makefiles
Generates makefiles for use with ``mingw32-make`` under a Windows command
prompt.
-Use this generator under a Windows command prompt with MinGW in the ``PATH``
+Use this generator under a Windows command prompt with
+MinGW (Minimalist GNU for Windows) in the ``PATH``
and using ``mingw32-make`` as the build tool. The generated makefiles use
``cmd.exe`` as the shell to launch build rules. They are not compatible with
MSYS or a unix shell.
diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst
index 3bbd9dcbe..51ef49b01 100644
--- a/Help/generator/Ninja.rst
+++ b/Help/generator/Ninja.rst
@@ -4,8 +4,8 @@ Ninja
Generates build.ninja files.
A build.ninja file is generated into the build tree. Recent versions
-of the ninja program can build the project through the "all" target.
-An "install" target is also provided.
+of the ninja program can build the project through the ``all`` target.
+An ``install`` target is also provided.
For each subdirectory ``sub/dir`` of the project, additional targets
are generated:
diff --git a/Help/generator/Sublime Text 2.rst b/Help/generator/Sublime Text 2.rst
index 0597a9528..0a07ea983 100644
--- a/Help/generator/Sublime Text 2.rst
+++ b/Help/generator/Sublime Text 2.rst
@@ -4,11 +4,11 @@ Sublime Text 2
Generates Sublime Text 2 project files.
Project files for Sublime Text 2 will be created in the top directory
-and in every subdirectory which features a CMakeLists.txt file
-containing a PROJECT() call. Additionally Makefiles (or build.ninja
-files) are generated into the build tree. The appropriate make
-program can build the project through the default make target. A
-"make install" target is also provided.
+and in every subdirectory which features a ``CMakeLists.txt`` file
+containing a :command:`project` call. Additionally ``Makefiles``
+(or ``build.ninja`` files) are generated into the build tree.
+The appropriate make program can build the project through the default ``all``
+target. An ``install`` target is also provided.
This "extra" generator may be specified as:
diff --git a/Help/generator/Unix Makefiles.rst b/Help/generator/Unix Makefiles.rst
index 97d74a853..1e65ee133 100644
--- a/Help/generator/Unix Makefiles.rst
+++ b/Help/generator/Unix Makefiles.rst
@@ -5,4 +5,4 @@ Generates standard UNIX makefiles.
A hierarchy of UNIX makefiles is generated into the build tree. Any
standard UNIX-style make program can build the project through the
-default make target. A "make install" target is also provided.
+default ``all`` target. An ``install`` target is also provided.
diff --git a/Help/generator/VS_TOOLSET_HOST_ARCH.txt b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
index 4eb900f81..029363115 100644
--- a/Help/generator/VS_TOOLSET_HOST_ARCH.txt
+++ b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
@@ -1,6 +1,6 @@
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).
+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.
diff --git a/Help/generator/Xcode.rst b/Help/generator/Xcode.rst
index 71430c7aa..d893ac504 100644
--- a/Help/generator/Xcode.rst
+++ b/Help/generator/Xcode.rst
@@ -3,9 +3,7 @@ Xcode
Generate Xcode project files.
-This supports Xcode 3.0 and above. Support for Xcode versions prior
-to Xcode 5 is deprecated and will be dropped in a future version of
-CMake.
+This supports Xcode 5.0 and above.
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/manual/LINKS.txt b/Help/manual/LINKS.txt
index 8e53c0c03..60a260c10 100644
--- a/Help/manual/LINKS.txt
+++ b/Help/manual/LINKS.txt
@@ -14,7 +14,7 @@ Online Documentation and Community Resources
Mailing List
https://cmake.org/mailing-lists
- For help and discussion about using cmake, a mailing list is
+ For help and discussion about using CMake, a mailing list is
provided at cmake@cmake.org. The list is member-post-only but one
may sign up on the CMake web page. Please first read the full
documentation at https://cmake.org before posting questions to
diff --git a/Help/manual/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt
index baa73d5e1..810aaa914 100644
--- a/Help/manual/OPTIONS_BUILD.txt
+++ b/Help/manual/OPTIONS_BUILD.txt
@@ -9,23 +9,23 @@
``-C <initial-cache>``
Pre-load a script to populate the cache.
- When cmake is first run in an empty build tree, it creates a
- CMakeCache.txt file and populates it with customizable settings for
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
the project. This option may be used to specify a file from which
to load cache entries before the first pass through the project's
- cmake listfiles. The loaded entries take priority over the
+ CMake listfiles. The loaded entries take priority over the
project's default values. The given file should be a CMake script
- containing SET commands that use the CACHE option, not a
+ containing :command:`set` commands that use the ``CACHE`` option, not a
cache-format file.
``-D <var>:<type>=<value>, -D <var>=<value>``
- Create or update a cmake cache entry.
+ Create or update a CMake ``CACHE`` entry.
- When cmake is first run in an empty build tree, it creates a
- CMakeCache.txt file and populates it with customizable settings for
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
the project. This option may be used to specify a setting that
takes priority over the project's default value. The option may be
- repeated for as many cache entries as desired.
+ repeated for as many ``CACHE`` entries as desired.
If the ``:<type>`` portion is given it must be one of the types
specified by the :command:`set` command documentation for its
@@ -39,14 +39,14 @@
``-D<var>:<type>=<value>`` or ``-D<var>=<value>``.
``-U <globbing_expr>``
- Remove matching entries from CMake cache.
+ Remove matching entries from CMake ``CACHE``.
This option may be used to remove one or more variables from the
- CMakeCache.txt file, globbing expressions using * and ? are
- supported. The option may be repeated for as many cache entries as
+ ``CMakeCache.txt`` file, globbing expressions using ``*`` and ``?`` are
+ supported. The option may be repeated for as many ``CACHE`` entries as
desired.
- Use with care, you can make your CMakeCache.txt non-working.
+ Use with care, you can make your ``CMakeCache.txt`` non-working.
``-G <generator-name>``
Specify a build system generator.
@@ -56,6 +56,9 @@
build system. Possible generator names are specified in the
:manual:`cmake-generators(7)` manual.
+ If not specified, CMake checks the :envvar:`CMAKE_GENERATOR` environment
+ variable and otherwise falls back to a builtin default selection.
+
``-T <toolset-spec>``
Toolset specification for the generator, if supported.
@@ -74,47 +77,47 @@
Suppress developer warnings.
Suppress warnings that are meant for the author of the
- CMakeLists.txt files. By default this will also turn off
+ ``CMakeLists.txt`` files. By default this will also turn off
deprecation warnings.
``-Wdev``
Enable developer warnings.
- Enable warnings that are meant for the author of the CMakeLists.txt
+ Enable warnings that are meant for the author of the ``CMakeLists.txt``
files. By default this will also turn on deprecation warnings.
``-Werror=dev``
Make developer warnings errors.
- Make warnings that are meant for the author of the CMakeLists.txt files
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files
errors. By default this will also turn on deprecated warnings as errors.
``-Wno-error=dev``
Make developer warnings not errors.
- Make warnings that are meant for the author of the CMakeLists.txt files not
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files not
errors. By default this will also turn off deprecated warnings as errors.
``-Wdeprecated``
Enable deprecated functionality warnings.
Enable warnings for usage of deprecated functionality, that are meant
- for the author of the CMakeLists.txt files.
+ for the author of the ``CMakeLists.txt`` files.
``-Wno-deprecated``
Suppress deprecated functionality warnings.
Suppress warnings for usage of deprecated functionality, that are meant
- for the author of the CMakeLists.txt files.
+ for the author of the ``CMakeLists.txt`` files.
``-Werror=deprecated``
Make deprecated macro and function warnings errors.
Make warnings for usage of deprecated macros and functions, that are meant
- for the author of the CMakeLists.txt files, errors.
+ for the author of the ``CMakeLists.txt`` files, errors.
``-Wno-error=deprecated``
Make deprecated macro and function warnings not errors.
Make warnings for usage of deprecated macros and functions, that are meant
- for the author of the CMakeLists.txt files, not errors.
+ for the author of the ``CMakeLists.txt`` files, not errors.
diff --git a/Help/manual/ccmake.1.rst b/Help/manual/ccmake.1.rst
index 954847150..60d45a35d 100644
--- a/Help/manual/ccmake.1.rst
+++ b/Help/manual/ccmake.1.rst
@@ -20,7 +20,7 @@ when the program is running.
CMake is a cross-platform build system generator. Projects specify
their build process with platform-independent CMake listfiles included
-in each directory of a source tree with the name CMakeLists.txt.
+in each directory of a source tree with the name ``CMakeLists.txt``.
Users build a project by using CMake to generate a build system for a
native tool on their platform.
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index a1328f230..8cd6e681f 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -21,7 +21,7 @@ Binary Targets
Executables and libraries are defined using the :command:`add_executable`
and :command:`add_library` commands. The resulting binary files have
-appropriate prefixes, suffixes and extensions for the platform targeted.
+appropriate :prop_tgt:`PREFIX`, :prop_tgt:`SUFFIX` and extensions for the platform targeted.
Dependencies between binary targets are expressed using the
:command:`target_link_libraries` command:
@@ -31,7 +31,7 @@ Dependencies between binary targets are expressed using the
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)
-``archive`` is defined as a static library -- an archive containing objects
+``archive`` is defined as a ``STATIC`` library -- an archive containing objects
compiled from ``archive.cpp``, ``zip.cpp``, and ``lzma.cpp``. ``zipapp``
is defined as an executable formed by compiling and linking ``zipapp.cpp``.
When linking the ``zipapp`` executable, the ``archive`` static library is
@@ -59,7 +59,7 @@ Binary Library Types
Normal Libraries
^^^^^^^^^^^^^^^^
-By default, the :command:`add_library` command defines a static library,
+By default, the :command:`add_library` command defines a ``STATIC`` library,
unless a type is specified. A type may be specified when using the command:
.. code-block:: cmake
@@ -141,8 +141,8 @@ Alternatively, object libraries may be linked into other targets:
target_link_libraries(test_exe archive)
The link (or archiving) step of those other targets will use the object
-files from object libraries that are *directly* linked. Additionally,
-usage requirements of the object libraries will be honored when compiling
+files from ``OBJECT`` libraries that are *directly* linked. Additionally,
+usage requirements of the ``OBJECT`` libraries will be honored when compiling
sources in those other targets. Furthermore, those usage requirements
will propagate transitively to dependents of those other targets.
@@ -365,8 +365,8 @@ non-compatible requirements :manual:`cmake(1)` issues a diagnostic:
target_link_libraries(exe2 lib1 lib2)
The ``lib1`` requirement ``INTERFACE_POSITION_INDEPENDENT_CODE`` is not
-"compatible" with the ``POSITION_INDEPENDENT_CODE`` property of the ``exe1``
-target. The library requires that consumers are built as
+"compatible" with the :prop_tgt:`POSITION_INDEPENDENT_CODE` property of
+the ``exe1`` target. The library requires that consumers are built as
position-independent-code, while the executable specifies to not built as
position-independent-code, so a diagnostic is issued.
@@ -547,10 +547,10 @@ is not known until build-time. Therefore, code such as
target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
endif()
-may appear to work for ``Makefile`` based and ``Ninja`` generators, but is not
-portable to IDE generators. Additionally, the :prop_tgt:`IMPORTED`
-configuration-mappings are not accounted for with code like this, so it should
-be avoided.
+may appear to work for :ref:`Makefile Generators` and :generator:`Ninja`
+generators, but is not portable to IDE generators. Additionally,
+the :prop_tgt:`IMPORTED` configuration-mappings are not accounted for
+with code like this, so it should be avoided.
The unary ``TARGET_PROPERTY`` generator expression and the ``TARGET_POLICY``
generator expression are evaluated with the consuming target context. This
@@ -699,7 +699,7 @@ found in those directories. This behavior for :ref:`imported targets` may
be controlled by setting the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` target
property on the *consumers* of imported targets.
-If a binary target is linked transitively to a Mac OX framework, the
+If a binary target is linked transitively to a macOS :prop_tgt:`FRAMEWORK`, the
``Headers`` directory of the framework is also treated as a usage requirement.
This has the same effect as passing the framework directory as an include
directory.
@@ -977,6 +977,7 @@ are:
* Properties matching ``INTERFACE_*``
* Built-in properties matching ``COMPATIBLE_INTERFACE_*``
* ``EXPORT_NAME``
+* ``EXPORT_PROPERTIES``
* ``IMPORTED``
* ``MANUALLY_ADDED_DEPENDENCIES``
* ``NAME``
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index c43341276..96ceb945a 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -23,6 +23,10 @@ Environment Variables that Control the Build
/envvar/CMAKE_BUILD_PARALLEL_LEVEL
/envvar/CMAKE_CONFIG_TYPE
+ /envvar/CMAKE_GENERATOR
+ /envvar/CMAKE_GENERATOR_INSTANCE
+ /envvar/CMAKE_GENERATOR_PLATFORM
+ /envvar/CMAKE_GENERATOR_TOOLSET
/envvar/CMAKE_MSVCIDE_RUN_PATH
/envvar/CMAKE_NO_VERBOSE
/envvar/CMAKE_OSX_ARCHITECTURES
@@ -52,6 +56,7 @@ Environment Variables for Languages
/envvar/FFLAGS
/envvar/RC
/envvar/RCFLAGS
+ /envvar/SWIFTC
Environment Variables for CTest
===============================
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index f3e02088a..04b6ed259 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -379,6 +379,8 @@ finds the file missing, that means a concurrent CMake has generated
a new reply. The client may simply start again by reading the new
reply index file.
+.. _`file-api object kinds`:
+
Object Kinds
============
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 7f484a42a..c0449fb4a 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -86,7 +86,7 @@ String Comparisons
``$<EQUAL:value1,value2>``
``1`` if ``value1`` and ``value2`` are numerically equal, else ``0``.
``$<IN_LIST:string,list>``
- ``1`` if ``string`` is member of the comma-separated ``list``, else ``0``.
+ ``1`` if ``string`` is member of the semicolon-separated ``list``, else ``0``.
Uses case-sensitive comparisons.
``$<VERSION_LESS:v1,v2>``
``1`` if ``v1`` is a version less than ``v2``, else ``0``.
@@ -110,21 +110,30 @@ Variable Queries
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_id>``
- ``1`` if the CMake-id of the platform matches ``platform_id``
- otherwise ``0``.
+``$<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_id>``
- ``1`` if the CMake-id of the C compiler matches ``compiler_id``,
- otherwise ``0``.
+``$<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_id>``
- ``1`` if the CMake-id of the CXX compiler matches ``compiler_id``,
- otherwise ``0``.
+``$<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.
-``$<Fortran_COMPILER_ID:compiler_id>``
- ``1`` if the CMake-id of the Fortran compiler matches ``compiler_id``,
- otherwise ``0``.
+``$<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.
+``$<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.
``$<C_COMPILER_VERSION:version>``
``1`` if the version of the C compiler matches ``version``, otherwise ``0``.
@@ -132,6 +141,9 @@ Variable Queries
``$<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>``
+ ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
``$<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.
@@ -152,10 +164,46 @@ Variable Queries
.. _`Boolean COMPILE_LANGUAGE Generator Expression`:
-``$<COMPILE_LANGUAGE:language>``
- ``1`` when the language used for compilation unit matches ``language``,
- otherwise ``0``. This expression may be used to specify compile options,
- compile definitions, and include directories for source files of a
+``$<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
+ for the combination of ``$<COMPILE_LANGUAGE:language>`` and
+ ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify
+ compile options, compile definitions, and include directories for source files of a
+ particular language and compiler combination in a target. For example:
+
+ .. code-block:: cmake
+
+ add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
+ target_compile_definitions(myapp
+ PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:COMPILING_CXX_WITH_CLANG>
+ $<$<COMPILE_LANG_AND_ID:CXX,Intel>:COMPILING_CXX_WITH_INTEL>
+ $<$<COMPILE_LANG_AND_ID:C,Clang>:COMPILING_C_WITH_CLANG>
+ )
+
+ This specifies the use of different compile definitions based on both
+ the compiler id and compilation language. This example will have a
+ ``COMPILING_CXX_WITH_CLANG`` compile definition when Clang is the CXX
+ compiler, and ``COMPILING_CXX_WITH_INTEL`` when Intel is the CXX compiler.
+ Likewise when the C compiler is Clang it will only see the ``COMPILING_C_WITH_CLANG``
+ definition.
+
+ Without the ``COMPILE_LANG_AND_ID`` generator expression the same logic
+ would be expressed as:
+
+ .. code-block:: cmake
+
+ target_compile_definitions(myapp
+ PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:Clang>>:COMPILING_CXX_WITH_CLANG>
+ $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:Intel>>:COMPILING_CXX_WITH_INTEL>
+ $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG>
+ )
+
+``$<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
particular language in a target. For example:
.. code-block:: cmake
@@ -169,7 +217,7 @@ Variable Queries
$<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA>
)
target_include_directories(myapp
- PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX,CUDA>:/opt/foo/headers>
)
This specifies the use of the ``-fno-exceptions`` compile option,
@@ -285,6 +333,10 @@ String Transformations
``$<JOIN:list,string>``
Joins the list with the content of ``string``.
+``$<REMOVE_DUPLICATES:list>``
+ Removes duplicated items in the given ``list``.
+``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+ Includes or removes items from ``list`` that match the regular expression ``regex``.
``$<LOWER_CASE:string>``
Content of ``string`` converted to lower case.
``$<UPPER_CASE:string>``
@@ -338,16 +390,19 @@ Variable Queries
``$<CONFIGURATION>``
Configuration name. Deprecated since CMake 3.0. Use ``CONFIG`` instead.
``$<PLATFORM_ID>``
- The CMake-id of the platform.
+ The current system's CMake platform id.
See also the :variable:`CMAKE_SYSTEM_NAME` variable.
``$<C_COMPILER_ID>``
- The CMake-id of the C compiler used.
+ The CMake's compiler id of the C compiler used.
See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
``$<CXX_COMPILER_ID>``
- The CMake-id of the CXX compiler used.
+ The CMake's compiler id of the CXX compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+``$<CUDA_COMPILER_ID>``
+ The CMake's compiler id of the CUDA compiler used.
See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
``$<Fortran_COMPILER_ID>``
- The CMake-id of the Fortran compiler used.
+ The CMake's compiler id of the Fortran compiler used.
See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
``$<C_COMPILER_VERSION>``
The version of the C compiler used.
@@ -355,6 +410,9 @@ Variable Queries
``$<CXX_COMPILER_VERSION>``
The version of the CXX compiler used.
See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+``$<CUDA_COMPILER_VERSION>``
+ The version of the CUDA compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
``$<Fortran_COMPILER_VERSION>``
The version of the Fortran compiler used.
See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
@@ -372,13 +430,85 @@ Target-Dependent Queries
Expands to the ``tgt`` if the given target exists, an empty string
otherwise.
``$<TARGET_FILE:tgt>``
- Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a target.
+ Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a
+ target.
+``$<TARGET_FILE_BASE_NAME:tgt>``
+ Base name of main file where ``tgt`` is the name of a target.
+
+ The base name corresponds to the target file name (see
+ ``$<TARGET_FILE_NAME:tgt>``) without prefix and suffix. For example, if
+ target file name is ``libbase.so``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ :prop_tgt:`LIBRARY_OUTPUT_NAME` and :prop_tgt:`RUNTIME_OUTPUT_NAME`
+ target properties and their configuration specific variants
+ :prop_tgt:`OUTPUT_NAME_<CONFIG>`, :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>`,
+ :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`RUNTIME_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+``$<TARGET_FILE_PREFIX:tgt>``
+ Prefix of main file where ``tgt`` is the name of a target.
+
+ 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>``
+ Suffix of main file where ``tgt`` is the name of a target.
+
+ The suffix corresponds to the file 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>``
Name of main file (.exe, .so.1.2, .a).
``$<TARGET_FILE_DIR:tgt>``
Directory of main file (.exe, .so.1.2, .a).
``$<TARGET_LINKER_FILE:tgt>``
File used to link (.a, .lib, .so) where ``tgt`` is the name of a target.
+``$<TARGET_LINKER_FILE_BASE_NAME:tgt>``
+ Base name of file used to link where ``tgt`` is the name of a target.
+
+ The base name corresponds to the target linker file name (see
+ ``$<TARGET_LINKER_FILE_NAME:tgt>``) without prefix and suffix. For example,
+ if target file name is ``libbase.a``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ and :prop_tgt:`LIBRARY_OUTPUT_NAME` target properties and their configuration
+ specific variants :prop_tgt:`OUTPUT_NAME_<CONFIG>`,
+ :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+``$<TARGET_LINKER_FILE_PREFIX:tgt>``
+ Prefix of file used to link where ``tgt`` is the name of a target.
+
+ See also the :prop_tgt:`PREFIX` and :prop_tgt:`IMPORT_PREFIX` target
+ properties.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+``$<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").
+
+ See also the :prop_tgt:`SUFFIX` and :prop_tgt:`IMPORT_SUFFIX` target
+ properties.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
``$<TARGET_LINKER_FILE_NAME:tgt>``
Name of file used to link (.a, .lib, .so).
``$<TARGET_LINKER_FILE_DIR:tgt>``
@@ -396,6 +526,22 @@ Target-Dependent Queries
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>``
+ Base name of the linker generated program database file (.pdb)
+ where ``tgt`` is the name of a target.
+
+ The base name corresponds to the target PDB file name (see
+ ``$<TARGET_PDB_FILE_NAME:tgt>``) without prefix and suffix. For example,
+ if target file name is ``base.pdb``, the base name is ``base``.
+
+ See also the :prop_tgt:`PDB_NAME` target property and its configuration
+ specific variant :prop_tgt:`PDB_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
``$<TARGET_PDB_FILE_NAME:tgt>``
Name of the linker generated program database file (.pdb).
``$<TARGET_PDB_FILE_DIR:tgt>``
@@ -449,12 +595,16 @@ Output-Related Expressions
Content of ``...`` converted to a C identifier. The conversion follows the
same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
``$<TARGET_OBJECTS:objLib>``
- List of objects resulting from build of ``objLib``. ``objLib`` must be an
- object of type ``OBJECT_LIBRARY``.
+ List of objects resulting from build of ``objLib``.
``$<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.
+ The ``...`` may be a :ref:`semicolon-separated list <CMake Language Lists>`
+ of paths, in which case each path is converted individually and a result
+ list is generated using the shell path separator (``:`` on POSIX and
+ ``;`` on Windows). Be sure to enclose the argument containing this genex
+ in double quotes in CMake source code so that ``;`` does not split arguments.
Debugging
=========
diff --git a/Help/manual/cmake-gui.1.rst b/Help/manual/cmake-gui.1.rst
index 856aa2fba..ff8311bbe 100644
--- a/Help/manual/cmake-gui.1.rst
+++ b/Help/manual/cmake-gui.1.rst
@@ -21,7 +21,7 @@ provided at the bottom of the window when the program is running.
CMake is a cross-platform build system generator. Projects specify
their build process with platform-independent CMake listfiles included
-in each directory of a source tree with the name CMakeLists.txt.
+in each directory of a source tree with the name ``CMakeLists.txt``.
Users build a project by using CMake to generate a build system for a
native tool on their platform.
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
index 5e5cffffd..4ca8e3a26 100644
--- a/Help/manual/cmake-language.7.rst
+++ b/Help/manual/cmake-language.7.rst
@@ -430,7 +430,7 @@ comments: a `Bracket Comment`_ and a `Line Comment`_.
Bracket Comment
^^^^^^^^^^^^^^^
-A ``#`` immediately followed by a `Bracket Argument`_ forms a
+A ``#`` immediately followed by a :token:`bracket_open` forms a
*bracket comment* consisting of the entire bracket enclosure:
.. raw:: latex
@@ -461,7 +461,7 @@ For example:
Line Comment
^^^^^^^^^^^^
-A ``#`` not immediately followed by a `Bracket Argument`_ forms a
+A ``#`` not immediately followed by a :token:`bracket_open` forms a
*line comment* that runs until the end of the line:
.. raw:: latex
@@ -469,7 +469,7 @@ A ``#`` not immediately followed by a `Bracket Argument`_ forms a
\begin{small}
.. productionlist::
- line_comment: '#' <any text not starting in a `bracket_argument`
+ line_comment: '#' <any text not starting in a `bracket_open`
: and not containing a `newline`>
.. raw:: latex
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d9b939f3b..fc4bfdc7a 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -125,6 +125,7 @@ They are normally called through the :command:`find_package` command.
/module/FindDCMTK
/module/FindDevIL
/module/FindDoxygen
+ /module/FindEnvModules
/module/FindEXPAT
/module/FindFLEX
/module/FindFLTK2
diff --git a/Help/manual/cmake-packages.7.rst b/Help/manual/cmake-packages.7.rst
index 876ca84d9..f5aa42dc7 100644
--- a/Help/manual/cmake-packages.7.rst
+++ b/Help/manual/cmake-packages.7.rst
@@ -12,7 +12,7 @@ Introduction
Packages provide dependency information to CMake based buildsystems. Packages
are found with the :command:`find_package` command. The result of
-using ``find_package`` is either a set of :prop_tgt:`IMPORTED` targets, or
+using :command:`find_package` is either a set of :prop_tgt:`IMPORTED` targets, or
a set of variables corresponding to build-relevant information.
Using Packages
@@ -647,12 +647,17 @@ Disabling the Package Registry
In some cases using the Package Registries is not desirable. CMake
allows one to disable them using the following variables:
- * :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` disables the
- :command:`export(PACKAGE)` command.
- * :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` disables the
- User Package Registry in all the :command:`find_package` calls.
- * :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` disables
- the System Package Registry in all the :command:`find_package` calls.
+* The :command:`export(PACKAGE)` command does not populate the user
+ package registry when :policy:`CMP0090` is set to ``NEW`` unless the
+ :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable explicitly enables it.
+ When :policy:`CMP0090` is *not* set to ``NEW`` then
+ :command:`export(PACKAGE)` populates the user package registry unless
+ the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable explicitly
+ disables it.
+* :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` disables the
+ User Package Registry in all the :command:`find_package` calls.
+* :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` disables
+ the System Package Registry in all the :command:`find_package` calls.
Package Registry Example
------------------------
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 409b5b1c7..1d023cb1a 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -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.15
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0094: FindPython3, FindPython2 and FindPython use LOCATION for lookup strategy. </policy/CMP0094>
+ CMP0093: FindBoost reports Boost_VERSION in x.y.z format. </policy/CMP0093>
+ CMP0092: MSVC warning flags are not in CMAKE_{C,CXX}_FLAGS by default. </policy/CMP0092>
+ CMP0091: MSVC runtime library flags are selected by an abstraction. </policy/CMP0091>
+ CMP0090: export(PACKAGE) does not populate package registry by default. </policy/CMP0090>
+ CMP0089: Compiler id for IBM Clang-based XL compilers is now XLClang. </policy/CMP0089>
+
Policies Introduced by CMake 3.14
=================================
@@ -65,6 +78,7 @@ Policies Introduced by CMake 3.14
CMP0083: Add PIE options when linking executable. </policy/CMP0083>
CMP0082: Install rules from add_subdirectory() are interleaved with those in caller. </policy/CMP0082>
+
Policies Introduced by CMake 3.13
=================================
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index ef864129b..77b1ae8a1 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -61,7 +61,7 @@ Properties on Directories
.. toctree::
:maxdepth: 1
- /prop_dir/ADDITIONAL_MAKE_CLEAN_FILES
+ /prop_dir/ADDITIONAL_CLEAN_FILES
/prop_dir/BINARY_DIR
/prop_dir/BUILDSYSTEM_TARGETS
/prop_dir/CACHE_VARIABLES
@@ -102,6 +102,7 @@ Properties on Targets
.. toctree::
:maxdepth: 1
+ /prop_tgt/ADDITIONAL_CLEAN_FILES
/prop_tgt/ALIASED_TARGET
/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
/prop_tgt/ANDROID_API
@@ -280,6 +281,7 @@ Properties on Targets
/prop_tgt/MACOSX_RPATH
/prop_tgt/MANUALLY_ADDED_DEPENDENCIES
/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG
+ /prop_tgt/MSVC_RUNTIME_LIBRARY
/prop_tgt/NAME
/prop_tgt/NO_SONAME
/prop_tgt/NO_SYSTEM_FROM_IMPORTED
@@ -312,6 +314,9 @@ Properties on Targets
/prop_tgt/STATIC_LIBRARY_FLAGS
/prop_tgt/STATIC_LIBRARY_OPTIONS
/prop_tgt/SUFFIX
+ /prop_tgt/Swift_DEPENDENCIES_FILE
+ /prop_tgt/Swift_MODULE_DIRECTORY
+ /prop_tgt/Swift_MODULE_NAME
/prop_tgt/TYPE
/prop_tgt/VERSION
/prop_tgt/VISIBILITY_INLINES_HIDDEN
@@ -332,8 +337,12 @@ Properties on Targets
/prop_tgt/VS_GLOBAL_variable
/prop_tgt/VS_IOT_EXTENSIONS_VERSION
/prop_tgt/VS_IOT_STARTUP_TASK
+ /prop_tgt/VS_JUST_MY_CODE_DEBUGGING
/prop_tgt/VS_KEYWORD
/prop_tgt/VS_MOBILE_EXTENSIONS_VERSION
+ /prop_tgt/VS_NO_SOLUTION_DEPLOY
+ /prop_tgt/VS_PACKAGE_REFERENCES
+ /prop_tgt/VS_PROJECT_IMPORT
/prop_tgt/VS_SCC_AUXPATH
/prop_tgt/VS_SCC_LOCALPATH
/prop_tgt/VS_SCC_PROJECTNAME
@@ -348,10 +357,12 @@ Properties on Targets
/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS
/prop_tgt/XCODE_ATTRIBUTE_an-attribute
/prop_tgt/XCODE_EXPLICIT_FILE_TYPE
+ /prop_tgt/XCODE_GENERATE_SCHEME
/prop_tgt/XCODE_PRODUCT_TYPE
/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER
/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
/prop_tgt/XCODE_SCHEME_ARGUMENTS
+ /prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT
/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
@@ -431,6 +442,8 @@ Properties on Source Files
/prop_sf/SKIP_AUTOMOC
/prop_sf/SKIP_AUTORCC
/prop_sf/SKIP_AUTOUIC
+ /prop_sf/Swift_DEPENDENCIES_FILE
+ /prop_sf/Swift_DIAGNOSTICS_FILE
/prop_sf/SYMBOLIC
/prop_sf/VS_COPY_TO_OUT_DIR
/prop_sf/VS_CSHARP_tagname
@@ -491,6 +504,7 @@ Deprecated Properties on Directories
.. toctree::
:maxdepth: 1
+ /prop_dir/ADDITIONAL_MAKE_CLEAN_FILES
/prop_dir/COMPILE_DEFINITIONS_CONFIG
/prop_dir/TEST_INCLUDE_FILE
diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index 25d364c61..8f10b9f0e 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -7,6 +7,11 @@ cmake-server(7)
.. 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
============
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index ba44b7f21..7435d9a77 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -26,13 +26,13 @@ built-in variables, such as
:variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` etc are set by
invoking the :command:`project` command. If no project command
is in the top-level CMakeLists file, one will be implicitly generated. By default
-the enabled languages are C and CXX:
+the enabled languages are ``C`` and ``CXX``:
.. code-block:: cmake
project(C_Only C)
-A special value of NONE can also be used with the :command:`project` command
+A special value of ``NONE`` can also be used with the :command:`project` command
to enable no languages:
.. code-block:: cmake
@@ -101,6 +101,14 @@ values for the compilers.
The :variable:`CMAKE_CROSSCOMPILING` variable is set to true when CMake is
cross-compiling.
+Note that using the :variable:`CMAKE_SOURCE_DIR` or :variable:`CMAKE_BINARY_DIR`
+variables inside a toolchain file is typically undesirable. The toolchain
+file is used in contexts where these variables have different values when used
+in different places (e.g. as part of a call to :command:`try_compile`). In most
+cases, where there is a need to evaluate paths inside a toolchain file, the more
+appropriate variable to use would be :variable:`CMAKE_CURRENT_LIST_DIR`, since
+it always has an unambiguous, predictable value.
+
Cross Compiling for Linux
-------------------------
@@ -468,10 +476,10 @@ The following variables will be computed and provided automatically:
The Android ABI detected from the standalone toolchain.
:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
- The absolute path prefix to the binutils in the standalone toolchain.
+ The absolute path prefix to the ``binutils`` in the standalone toolchain.
:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`
- The host platform suffix of the binutils in the standalone toolchain.
+ The host platform suffix of the ``binutils`` in the standalone toolchain.
For example, a toolchain file might contain:
@@ -533,7 +541,7 @@ generator is recommended. The :generator:`Unix Makefiles` or
:generator:`Ninja` generators can also be used, but they require the
project to handle more areas like target CPU selection and code signing.
-Any of the three systems can be targetted by setting the
+Any of the three systems can be targeted by setting the
:variable:`CMAKE_SYSTEM_NAME` variable to a value from the table below.
By default, the latest Device SDK is chosen. As for all Apple platforms,
a different SDK (e.g. a simulator) can be selected by setting the
@@ -609,7 +617,7 @@ Code Signing
Some build artifacts for the embedded Apple platforms require mandatory
code signing. If the :generator:`Xcode` generator is being used and
-code signing is required or desired, the developmemt team ID can be
+code signing is required or desired, the development team ID can be
specified via the ``CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM`` CMake variable.
This team ID will then be included in the generated Xcode project.
By default, CMake avoids the need for code signing during the internal
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 5c494b890..75ddd5dd3 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -7,7 +7,7 @@ cmake-variables(7)
.. contents::
-This page documents variables that are provided by CMake
+This page documents variables that are provided by CMake
or have meaning to CMake when set by project code.
For general information on variables, see the
@@ -97,6 +97,7 @@ Variables that Provide Information
/variable/CMAKE_SOURCE_DIR
/variable/CMAKE_STATIC_LIBRARY_PREFIX
/variable/CMAKE_STATIC_LIBRARY_SUFFIX
+ /variable/CMAKE_Swift_MODULE_DIRECTORY
/variable/CMAKE_TOOLCHAIN_FILE
/variable/CMAKE_TWEAK_VERSION
/variable/CMAKE_VERBOSE_MAKEFILE
@@ -159,7 +160,9 @@ Variables that Change Behavior
/variable/CMAKE_ECLIPSE_VERSION
/variable/CMAKE_ERROR_DEPRECATED
/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+ /variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
/variable/CMAKE_EXPORT_COMPILE_COMMANDS
+ /variable/CMAKE_EXPORT_PACKAGE_REGISTRY
/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY
/variable/CMAKE_FIND_APPBUNDLE
/variable/CMAKE_FIND_FRAMEWORK
@@ -169,6 +172,7 @@ Variables that Change Behavior
/variable/CMAKE_FIND_NO_INSTALL_PREFIX
/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+ /variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG
/variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS
/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE
/variable/CMAKE_FIND_ROOT_PATH
@@ -195,6 +199,8 @@ Variables that Change Behavior
/variable/CMAKE_POLICY_WARNING_CMPNNNN
/variable/CMAKE_PREFIX_PATH
/variable/CMAKE_PROGRAM_PATH
+ /variable/CMAKE_PROJECT_INCLUDE
+ /variable/CMAKE_PROJECT_INCLUDE_BEFORE
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
/variable/CMAKE_STAGING_PREFIX
@@ -345,6 +351,7 @@ Variables that Control the Build
/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT
/variable/CMAKE_EXE_LINKER_FLAGS_INIT
/variable/CMAKE_FOLDER
+ /variable/CMAKE_FRAMEWORK
/variable/CMAKE_Fortran_FORMAT
/variable/CMAKE_Fortran_MODULE_DIRECTORY
/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE
@@ -384,6 +391,7 @@ Variables that Control the Build
/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT
/variable/CMAKE_MODULE_LINKER_FLAGS_INIT
/variable/CMAKE_MSVCIDE_RUN_PATH
+ /variable/CMAKE_MSVC_RUNTIME_LIBRARY
/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
/variable/CMAKE_NO_BUILTIN_CHRPATH
/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED
@@ -413,6 +421,7 @@ Variables that Control the Build
/variable/CMAKE_VS_GLOBALS
/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
/variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
+ /variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING
/variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
/variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES
/variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES
@@ -578,6 +587,7 @@ Variables for CTest
/variable/CTEST_UPDATE_COMMAND
/variable/CTEST_UPDATE_OPTIONS
/variable/CTEST_UPDATE_VERSION_ONLY
+ /variable/CTEST_UPDATE_VERSION_OVERRIDE
/variable/CTEST_USE_LAUNCHERS
Variables for CPack
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index f3b81ecb6..7b5399d21 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -16,6 +16,9 @@ Synopsis
`Build a Project`_
cmake --build <dir> [<options>] [-- <build-tool-options>]
+ `Install a Project`_
+ cmake --install <dir> [<options>]
+
`Open a Project`_
cmake --open <dir>
@@ -39,8 +42,8 @@ buildsystem generator CMake. The above `Synopsis`_ lists various actions
the tool can perform as described in sections below.
To build a software project with CMake, `Generate a Project Buildsystem`_.
-Optionally use **cmake** to `Build a Project`_ or just run the
-corresponding build tool (e.g. ``make``) directly. **cmake** can also
+Optionally use **cmake** to `Build a Project`_, `Install a Project`_ or just
+run the corresponding build tool (e.g. ``make``) directly. **cmake** can also
be used to `View Help`_.
The other actions are meant for use by software developers writing
@@ -169,12 +172,12 @@ Options
``-L[A][H]``
List non-advanced cached variables.
- List cache variables will run CMake and list all the variables from
- the CMake cache that are not marked as INTERNAL or ADVANCED. This
- will effectively display current CMake settings, which can then be
- changed with -D option. Changing some of the variables may result
- in more variables being created. If A is specified, then it will
- display also advanced variables. If H is specified, it will also
+ List ``CACHE`` variables will run CMake and list all the variables from
+ the CMake ``CACHE`` that are not marked as ``INTERNAL`` or :prop_cache:`ADVANCED`.
+ This will effectively display current CMake settings, which can then be
+ changed with ``-D`` option. Changing some of the variables may result
+ in more variables being created. If ``A`` is specified, then it will
+ display also advanced variables. If ``H`` is specified, it will also
display help for each variable.
``-N``
@@ -197,10 +200,17 @@ Options
from the top of a binary tree for a CMake project it will dump
additional information such as the cache, log files etc.
+``--loglevel=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>``
+ Set the log level.
+
+ The :command:`message` command will only output messages of the specified
+ log level or higher. The default log level is ``STATUS``.
+
``--debug-trycompile``
- Do not delete the try_compile build tree. Only useful on one try_compile at a time.
+ Do not delete the :command:`try_compile` build tree.
+ Only useful on one :command:`try_compile` at a time.
- Do not delete the files and directories created for try_compile
+ Do not delete the files and directories created for :command:`try_compile`
calls. This is useful in debugging failed try_compiles. It may
however change the results of the try-compiles as old junk from a
previous try-compile may cause a different test to either pass or
@@ -211,7 +221,7 @@ Options
Put cmake in a debug mode.
Print extra information during the cmake run like stack traces with
- message(send_error ) calls.
+ :command:`message(SEND_ERROR)` calls.
``--trace``
Put cmake in trace mode.
@@ -248,8 +258,8 @@ Options
Find problems with variable usage in system files.
Normally, unused and uninitialized variables are searched for only
- in CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR. This flag tells CMake to
- warn about other files as well.
+ in :variable:`CMAKE_SOURCE_DIR` and :variable:`CMAKE_BINARY_DIR`.
+ This flag tells CMake to warn about other files as well.
.. _`Build Tool Mode`:
@@ -269,15 +279,19 @@ following options:
``--build <dir>``
Project binary directory to be built. This is required and must be first.
-``-j [<jobs>], --parallel [<jobs>]``
+``--parallel [<jobs>], -j [<jobs>]``
The maximum number of concurrent processes to use when building.
If ``<jobs>`` is omitted the native build tool's default number is used.
The :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` environment variable, if set,
specifies a default parallel level when this option is not given.
-``--target <tgt>``
- Build ``<tgt>`` instead of default targets. May only be specified once.
+ Some native build tools always build in parallel. The use of ``<jobs>``
+ value of ``1`` can be used to limit to a single job.
+
+``--target <tgt>..., -t <tgt>...``
+ Build ``<tgt>`` instead of the default target. Multiple targets may be
+ given, separated by spaces.
``--config <cfg>``
For multi-configuration tools, choose configuration ``<cfg>``.
@@ -289,7 +303,7 @@ following options:
``--use-stderr``
Ignored. Behavior is default in CMake >= 3.0.
-``-v, --verbose``
+``--verbose, -v``
Enable verbose output - if supported - including the build commands to be
executed.
@@ -302,6 +316,41 @@ following options:
Run ``cmake --build`` with no options for quick help.
+Install a Project
+=================
+
+CMake provides a command-line signature to install an already-generated
+project binary tree:
+
+.. code-block:: shell
+
+ cmake --install <dir> [<options>]
+
+This may be used after building a project to run installation without
+using the generated build system or the native build tool.
+The options are:
+
+``--install <dir>``
+ Project binary directory to install. This is required and must be first.
+
+``--config <cfg>``
+ For multi-configuration generators, choose configuration ``<cfg>``.
+
+``--component <comp>``
+ Component-based install. Only install component ``<comp>``.
+
+``--prefix <prefix>``
+ Override the installation prefix, :variable:`CMAKE_INSTALL_PREFIX`.
+
+``--strip``
+ Strip before installing.
+
+``-v, --verbose``
+ Enable verbose output.
+
+ This option can be omitted if :envvar:`VERBOSE` environment variable is set.
+
+Run ``cmake --install`` with no options for quick help.
Open a Project
==============
@@ -325,8 +374,8 @@ Run a Script
Process the given cmake file as a script written in the CMake
language. No configure or generate step is performed and the cache
-is not modified. If variables are defined using -D, this must be
-done before the -P argument.
+is not modified. If variables are defined using ``-D``, this must be
+done before the ``-P`` argument.
Run a Command-Line Tool
@@ -375,6 +424,22 @@ Available commands are:
A list of strings with all the extra generators compatible with
the generator.
+ ``fileApi``
+ Optional member that is present when the :manual:`cmake-file-api(7)`
+ is available. The value is a JSON object with one member:
+
+ ``requests``
+ A JSON array containing zero or more supported file-api requests.
+ Each request is a JSON object with members:
+
+ ``kind``
+ Specifies one of the supported :ref:`file-api object kinds`.
+
+ ``version``
+ A JSON array whose elements are each a JSON object containing
+ ``major`` and ``minor`` members specifying non-negative integer
+ version components.
+
``serverMode``
``true`` if cmake supports server-mode and ``false`` otherwise.
@@ -383,23 +448,27 @@ Available commands are:
``compare_files [--ignore-eol] <file1> <file2>``
Check if ``<file1>`` is same as ``<file2>``. If files are the same,
- then returns 0, if not it returns 1. The ``--ignore-eol`` option
+ then returns ``0``, if not it returns ``1``. The ``--ignore-eol`` option
implies line-wise comparison and ignores LF/CRLF differences.
``copy <file>... <destination>``
Copy files to ``<destination>`` (either file or directory).
If multiple files are specified, the ``<destination>`` must be
directory and it must exist. Wildcards are not supported.
+ ``copy`` does follow symlinks. That means it does not copy symlinks,
+ but the files or directories it point to.
``copy_directory <dir>... <destination>``
Copy directories to ``<destination>`` directory.
If ``<destination>`` directory does not exist it will be created.
+ ``copy_directory`` does follow symlinks.
``copy_if_different <file>... <destination>``
Copy files to ``<destination>`` (either file or directory) if
they have changed.
If multiple files are specified, the ``<destination>`` must be
directory and it must exist.
+ ``copy_if_different`` does follow symlinks.
``echo [<string>...]``
Displays arguments as text.
@@ -459,13 +528,16 @@ Available commands are:
exist, the command returns a non-zero exit code, but no message
is logged. The ``-f`` option changes the behavior to return a
zero exit code (i.e. success) in such situations instead.
+ ``remove`` does not follow symlinks. That means it remove only symlinks
+ and not files it point to.
-``remove_directory <dir>``
- Remove a directory and its contents. If a directory does
+``remove_directory <dir>...``
+ Remove ``<dir>`` directories and their contents. If a directory does
not exist it will be silently ignored.
``rename <oldname> <newname>``
- Rename a file or directory (on one volume).
+ Rename a file or directory (on one volume). If file with the ``<newname>`` name
+ already exists, then it will be silently replaced.
``server``
Launch :manual:`cmake-server(7)` mode.
@@ -473,31 +545,56 @@ Available commands are:
``sleep <number>...``
Sleep for given number of seconds.
-``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<file>...]``
+``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<pathname>...]``
Create or extract a tar or zip archive. Options are:
- ``--``
- Stop interpreting options and treat all remaining arguments
- as file names even if they start in ``-``.
+ ``c``
+ Create a new archive containing the specified files.
+ If used, the ``<pathname>...`` argument is mandatory.
+ ``x``
+ Extract to disk from the archive.
+ The ``<pathname>...`` argument could be used to extract only selected files
+ or directories.
+ When extracting selected files or directories, you must provide their exact
+ names including the path, as printed by list (``-t``).
+ ``t``
+ List archive contents.
+ The ``<pathname>...`` argument could be used to list only selected files
+ or directories.
+ ``v``
+ Produce verbose output.
+ ``z``
+ Compress the resulting archive with gzip.
+ ``j``
+ Compress the resulting archive with bzip2.
+ ``J``
+ Compress the resulting archive with XZ.
+ ``--zstd``
+ Compress the resulting archive with Zstandard.
``--files-from=<file>``
Read file names from the given file, one per line.
Blank lines are ignored. Lines may not start in ``-``
except for ``--add-file=<name>`` to add files whose
names start in ``-``.
- ``--mtime=<date>``
- Specify modification time recorded in tarball entries.
``--format=<format>``
Specify the format of the archive to be created.
Supported formats are: ``7zip``, ``gnutar``, ``pax``,
``paxr`` (restricted pax, default), and ``zip``.
+ ``--mtime=<date>``
+ Specify modification time recorded in tarball entries.
+ ``--``
+ Stop interpreting options and treat all remaining arguments
+ as file names, even if they start with ``-``.
+
``time <command> [<args>...]``
Run command and display elapsed time.
-``touch <file>``
- Touch a file.
+``touch <file>...``
+ Creates ``<file>`` if file do not exist.
+ If ``<file>`` exists, it is changing ``<file>`` access and modification times.
-``touch_nocreate <file>``
+``touch_nocreate <file>...``
Touch a file if it exists but do not create it. If a file does
not exist it will be silently ignored.
diff --git a/Help/manual/cpack.1.rst b/Help/manual/cpack.1.rst
index 679c5478e..10f617e68 100644
--- a/Help/manual/cpack.1.rst
+++ b/Help/manual/cpack.1.rst
@@ -63,7 +63,7 @@ Options
details. By default, ``CPackConfig.cmake`` in the current directory will
be used.
-``--verbose,-V``
+``--verbose, -V``
Run ``cpack`` with verbose output. This can be used to show more details
from the package generation tools and is suitable for project developers.
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index d1bd69b66..5773176e6 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -22,8 +22,8 @@ Description
The **ctest** executable is the CMake test driver program.
CMake-generated build trees created for projects that use the
-ENABLE_TESTING and ADD_TEST commands have testing support. This
-program will run the tests and report results.
+:command:`enable_testing` and :command:`add_test` commands have testing support.
+This program will run the tests and report results.
Options
=======
@@ -33,8 +33,8 @@ Options
Some CMake-generated build trees can have multiple build
configurations in the same tree. This option can be used to specify
- which one should be tested. Example configurations are "Debug" and
- "Release".
+ which one should be tested. Example configurations are ``Debug`` and
+ ``Release``.
``--progress``
Enable short progress output from tests.
@@ -108,7 +108,7 @@ Options
``-O <file>, --output-log <file>``
Output to log file.
- This option tells CTest to write all its output to a log file.
+ This option tells CTest to write all its output to a ``<file>`` log file.
``-N,--show-only[=<format>]``
Disable actual execution of tests.
@@ -172,9 +172,10 @@ Options
Execute dashboard test.
This option tells CTest to act as a CDash client and perform a
- dashboard test. All tests are <Mode><Test>, where Mode can be
- Experimental, Nightly, and Continuous, and Test can be Start,
- Update, Configure, Build, Test, Coverage, and Submit.
+ dashboard test. All tests are ``<Mode><Test>``, where ``<Mode>`` can be
+ ``Experimental``, ``Nightly``, and ``Continuous``, and ``<Test>`` can be
+ ``Start``, ``Update``, ``Configure``, ``Build``, ``Test``,
+ ``Coverage``, and ``Submit``.
See `Dashboard Client`_.
@@ -229,10 +230,10 @@ Options
``-I [Start,End,Stride,test#,test#|Test file], --tests-information``
Run a specific number of tests by number.
- This option causes CTest to run tests starting at number Start,
- ending at number End, and incrementing by Stride. Any additional
- numbers after Stride are considered individual test numbers. Start,
- End,or stride can be empty. Optionally a file can be given that
+ This option causes CTest to run tests starting at number ``Start``,
+ ending at number ``End``, and incrementing by ``Stride``. Any additional
+ numbers after ``Stride`` are considered individual test numbers. ``Start``,
+ ``End``, or ``Stride`` can be empty. Optionally a file can be given that
contains the same syntax as the command line.
``-U, --union``
@@ -264,12 +265,12 @@ Options
name which can be very annoying.
``--interactive-debug-mode [0|1]``
- Set the interactive mode to 0 or 1.
+ Set the interactive mode to ``0`` or ``1``.
This option causes CTest to run tests in either an interactive mode
or a non-interactive mode. On Windows this means that in
non-interactive mode, all system debug pop up windows are blocked.
- In dashboard mode (Experimental, Nightly, Continuous), the default
+ In dashboard mode (``Experimental``, ``Nightly``, ``Continuous``), the default
is non-interactive. When just running tests not for a dashboard the
default is to allow popups and interactive debugging.
@@ -350,7 +351,7 @@ See `Build and Test Mode`_.
Label and Subproject Summary
============================
-CTest prints timing summary information for each label and subproject
+CTest prints timing summary information for each ``LABEL`` and subproject
associated with the tests run. The label time summary will not include labels
that are mapped to subprojects.
@@ -358,8 +359,8 @@ When the :prop_test:`PROCESSORS` test property is set, CTest will display a
weighted test timing result in label and subproject summaries. The time is
reported with `sec*proc` instead of just `sec`.
-The weighted time summary reported for each label or subproject j is computed
-as::
+The weighted time summary reported for each label or subproject ``j``
+is computed as::
Weighted Time Summary for Label/Subproject j =
sum(raw_test_time[j,i] * num_processors[j,i], i=1...num_tests[j])
@@ -368,25 +369,25 @@ as::
where:
-* raw_test_time[j,i]: Wall-clock time for the ith test for the jth label or
- subproject
-* num_processors[j,i]: Value of the CTest PROCESSORS property for the ith test
- for the jth label or subproject
-* num_tests[j]: Number of tests associated with the jth label or subproject
-* total: Total number of labels or subprojects that have at least one test run
+* ``raw_test_time[j,i]``: Wall-clock time for the ``i`` test
+ for the ``j`` label or subproject
+* ``num_processors[j,i]``: Value of the CTest :prop_test:`PROCESSORS` property
+ for the ``i`` test for the ``j`` label or subproject
+* ``num_tests[j]``: Number of tests associated with the ``j`` label or subproject
+* ``total``: Total number of labels or subprojects that have at least one test run
Therefore, the weighted time summary for each label or subproject represents
the amount of time that CTest gave to run the tests for each label or
subproject and gives a good representation of the total expense of the tests
for each label or subproject when compared to other labels or subprojects.
-For example, if "SubprojectA" showed "100 sec*proc" and "SubprojectB" showed
-"10 sec*proc", then CTest allocated approximately 10 times the CPU/core time
-to run the tests for "SubprojectA" than for "SubprojectB" (e.g. so if effort
+For example, if ``SubprojectA`` showed ``100 sec*proc`` and ``SubprojectB`` showed
+``10 sec*proc``, then CTest allocated approximately 10 times the CPU/core time
+to run the tests for ``SubprojectA`` than for ``SubprojectB`` (e.g. so if effort
is going to be expended to reduce the cost of the test suite for the whole
-project, then reducing the cost of the test suite for "SubprojectA" would
+project, then reducing the cost of the test suite for ``SubprojectA`` would
likely have a larger impact than effort to reduce the cost of the test suite
-for "SubprojectB").
+for ``SubprojectB``).
.. _`Build and Test Mode`:
@@ -449,7 +450,7 @@ this mode include:
``--build-config-sample``
A sample executable to use to determine the configuration that
- should be used. e.g. Debug/Release/etc.
+ should be used. e.g. ``Debug``, ``Release`` etc.
``--build-options``
Additional options for configuring the build (i.e. for CMake, not for
@@ -495,7 +496,7 @@ Options for Dashboard Client include:
dashboard.
``--tomorrow-tag``
- Nightly or experimental starts with next day tag.
+ ``Nightly`` or ``Experimental`` starts with next day tag.
This is useful if the build will not finish in one day.
@@ -505,10 +506,10 @@ Options for Dashboard Client include:
This option will submit extra files to the dashboard.
``--http1.0``
- Submit using HTTP 1.0.
+ Submit using `HTTP 1.0`.
- This option will force CTest to use HTTP 1.0 to submit files to the
- dashboard, instead of HTTP 1.1.
+ This option will force CTest to use `HTTP 1.0` to submit files to the
+ dashboard, instead of `HTTP 1.1`.
``--no-compress-output``
Do not compress test output when submitting.
@@ -711,7 +712,7 @@ Configuration settings to specify the version control tool include:
The source tree is updated by ``git fetch`` followed by
``git reset --hard`` to the ``FETCH_HEAD``. The result is the same
- as ``git pull`` except that any local moficiations are overwritten.
+ as ``git pull`` except that any local modifications are overwritten.
Use ``GITUpdateCustom`` to specify a different approach.
``GITInitSubmodules``
@@ -821,6 +822,8 @@ Configuration settings to specify the version control tool include:
* :module:`CTest` module variable: ``UPDATE_TYPE`` if set,
else ``CTEST_UPDATE_TYPE``
+.. _`UpdateVersionOnly`:
+
``UpdateVersionOnly``
Specify that you want the version control update command to only
discover the current version that is checked out, and not to update
@@ -828,6 +831,18 @@ Configuration settings to specify the version control tool include:
* `CTest Script`_ variable: :variable:`CTEST_UPDATE_VERSION_ONLY`
+.. _`UpdateVersionOverride`:
+
+``UpdateVersionOverride``
+ Specify the current version of your source tree.
+
+ When this variable is set to a non-empty string, CTest will report the value
+ you specified rather than using the update command to discover the current
+ version that is checked out. Use of this variable supersedes
+ ``UpdateVersionOnly``. Like ``UpdateVersionOnly``, using this variable tells
+ CTest not to update the source tree to a different version.
+
+ * `CTest Script`_ variable: :variable:`CTEST_UPDATE_VERSION_OVERRIDE`
Additional configuration settings include:
diff --git a/Help/module/CPackWIX.rst b/Help/module/CPackWIX.rst
index c88c7232c..fd378b86a 100644
--- a/Help/module/CPackWIX.rst
+++ b/Help/module/CPackWIX.rst
@@ -1,4 +1,5 @@
CPackWIX
--------
-The documentation for the CPack WIX generator has moved here: :cpack_gen:`CPack WIX Generator`
+The documentation for the CPack WIX generator has moved here:
+:cpack_gen:`CPack WIX Generator`
diff --git a/Help/module/FindEnvModules.rst b/Help/module/FindEnvModules.rst
new file mode 100644
index 000000000..72c120f22
--- /dev/null
+++ b/Help/module/FindEnvModules.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindEnvModules.cmake
diff --git a/Help/policy/CMP0000.rst b/Help/policy/CMP0000.rst
index 97ea633b2..aecfa7187 100644
--- a/Help/policy/CMP0000.rst
+++ b/Help/policy/CMP0000.rst
@@ -7,25 +7,27 @@ CMake requires that projects specify the version of CMake to which
they have been written. This policy has been put in place so users
trying to build the project may be told when they need to update their
CMake. Specifying a version also helps the project build with CMake
-versions newer than that specified. Use the cmake_minimum_required
-command at the top of your main CMakeLists.txt file:
+versions newer than that specified. Use the :command:`cmake_minimum_required`
+command at the top of your main ``CMakeLists.txt`` file:
::
cmake_minimum_required(VERSION <major>.<minor>)
-where "<major>.<minor>" is the version of CMake you want to support
-(such as "2.6"). The command will ensure that at least the given
+where ``<major>.<minor>`` is the version of CMake you want to support
+(such as ``3.14``). The command will ensure that at least the given
version of CMake is running and help newer versions be compatible with
-the project. See documentation of cmake_minimum_required for details.
+the project. See documentation of :command:`cmake_minimum_required` for
+details.
-Note that the command invocation must appear in the CMakeLists.txt
+Note that the command invocation must appear in the ``CMakeLists.txt``
file itself; a call in an included file is not sufficient. However,
-the cmake_policy command may be called to set policy CMP0000 to OLD or
-NEW behavior explicitly. The OLD behavior is to silently ignore the
-missing invocation. The NEW behavior is to issue an error instead of
-a warning. An included file may set CMP0000 explicitly to affect how
-this policy is enforced for the main CMakeLists.txt file.
+the :command:`cmake_policy` command may be called to set policy ``CMP0000``
+to ``OLD`` or ``NEW`` behavior explicitly. The ``OLD`` behavior is to
+silently ignore the missing invocation. The ``NEW`` behavior is to issue
+an error instead of a warning. An included file may set ``CMP0000``
+explicitly to affect how this policy is enforced for the main
+``CMakeLists.txt`` file.
This policy was introduced in CMake version 2.6.0.
diff --git a/Help/policy/CMP0001.rst b/Help/policy/CMP0001.rst
index 09ad38702..6fa64d983 100644
--- a/Help/policy/CMP0001.rst
+++ b/Help/policy/CMP0001.rst
@@ -1,21 +1,21 @@
CMP0001
-------
-CMAKE_BACKWARDS_COMPATIBILITY should no longer be used.
+``CMAKE_BACKWARDS_COMPATIBILITY`` should no longer be used.
-The OLD behavior is to check CMAKE_BACKWARDS_COMPATIBILITY and present
-it to the user. The NEW behavior is to ignore
+The behavior is to check ``CMAKE_BACKWARDS_COMPATIBILITY`` and present
+it to the user. The ``NEW`` behavior is to ignore
CMAKE_BACKWARDS_COMPATIBILITY completely.
-In CMake 2.4 and below the variable CMAKE_BACKWARDS_COMPATIBILITY was
+In CMake 2.4 and below the variable ``CMAKE_BACKWARDS_COMPATIBILITY`` was
used to request compatibility with earlier versions of CMake. In
CMake 2.6 and above all compatibility issues are handled by policies
-and the cmake_policy command. However, CMake must still check
-CMAKE_BACKWARDS_COMPATIBILITY for projects written for CMake 2.4 and
+and the :command:`cmake_policy` command. However, CMake must still check
+``CMAKE_BACKWARDS_COMPATIBILITY`` for projects written for CMake 2.4 and
below.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0002.rst b/Help/policy/CMP0002.rst
index 7cc53efa1..dc68d5180 100644
--- a/Help/policy/CMP0002.rst
+++ b/Help/policy/CMP0002.rst
@@ -3,8 +3,8 @@ CMP0002
Logical target names must be globally unique.
-Targets names created with add_executable, add_library, or
-add_custom_target are logical build target names. Logical target
+Targets names created with :command:`add_executable`, :command:`add_library`, or
+:command:`add_custom_target` are logical build target names. Logical target
names must be globally unique because:
::
@@ -16,13 +16,13 @@ names must be globally unique because:
The logical name of executable and library targets does not have to
correspond to the physical file names built. Consider using the
-OUTPUT_NAME target property to create two targets with the same
+:prop_tgt:`OUTPUT_NAME` target property to create two targets with the same
physical name while keeping logical names distinct. Custom targets
must simply have globally unique names (unless one uses the global
-property ALLOW_DUPLICATE_CUSTOM_TARGETS with a Makefiles generator).
+property :prop_gbl:`ALLOW_DUPLICATE_CUSTOM_TARGETS` with a Makefiles generator).
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0003.rst b/Help/policy/CMP0003.rst
index 16b045165..dd90883dc 100644
--- a/Help/policy/CMP0003.rst
+++ b/Help/policy/CMP0003.rst
@@ -37,7 +37,7 @@ Unfortunately this change can break code like
target_link_libraries(myexe /path/to/libA.so B)
-where "B" is meant to find "/path/to/libB.so". This code is wrong
+where ``B`` is meant to find ``/path/to/libB.so``. This code is wrong
because the user is asking the linker to find library B but has not
provided a linker search path (which may be added with the
link_directories command). However, with the old linking
@@ -45,9 +45,9 @@ implementation the code would work accidentally because the linker
search path added for library A allowed library B to be found.
In order to support projects depending on linker search paths added by
-linking to libraries with known full paths, the OLD behavior for this
+linking to libraries with known full paths, the ``OLD`` behavior for this
policy will add the linker search paths even though they are not
-needed for their own libraries. When this policy is set to OLD, CMake
+needed for their own libraries. When this policy is set to ``OLD``, CMake
will produce a link line such as
::
@@ -98,7 +98,7 @@ target. This avoids flooding users with messages for every target
when setting the policy once will probably fix all targets.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0004.rst b/Help/policy/CMP0004.rst
index 55da4d293..be6d3079b 100644
--- a/Help/policy/CMP0004.rst
+++ b/Help/policy/CMP0004.rst
@@ -12,14 +12,15 @@ whitespace from libraries linked with code like
This could lead to subtle errors in user projects.
-The OLD behavior for this policy is to silently remove leading and
-trailing whitespace. The NEW behavior for this policy is to diagnose
+The ``OLD`` behavior for this policy is to silently remove leading and
+trailing whitespace. The ``NEW`` behavior for this policy is to diagnose
the existence of such whitespace as an error. The setting for this
policy used when checking the library names is that in effect when the
-target is created by an add_executable or add_library command.
+target is created by an :command:`add_executable` or :command:`add_library`
+command.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0005.rst b/Help/policy/CMP0005.rst
index 66d125fb7..59567d56e 100644
--- a/Help/policy/CMP0005.rst
+++ b/Help/policy/CMP0005.rst
@@ -12,15 +12,15 @@ CMake versions 2.6 and above support escaping of most values, but
cannot assume the user has not added escapes already in an attempt to
work around limitations in earlier versions.
-The OLD behavior for this policy is to place definition values given
+The ``OLD`` behavior for this policy is to place definition values given
to add_definitions directly in the generated build rules without
-attempting to escape anything. The NEW behavior for this policy is to
+attempting to escape anything. The ``NEW`` behavior for this policy is to
generate correct escapes for all native build tools automatically.
-See documentation of the COMPILE_DEFINITIONS target property for
+See documentation of the ``COMPILE_DEFINITIONS`` target property for
limitations of the escaping implementation.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0006.rst b/Help/policy/CMP0006.rst
index d1b9ece7f..181958b39 100644
--- a/Help/policy/CMP0006.rst
+++ b/Help/policy/CMP0006.rst
@@ -1,24 +1,24 @@
CMP0006
-------
-Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION.
+Installing :prop_tgt:`MACOSX_BUNDLE` targets requires a ``BUNDLE DESTINATION``.
-This policy determines whether the install(TARGETS) command must be
-given a BUNDLE DESTINATION when asked to install a target with the
-MACOSX_BUNDLE property set. CMake 2.4 and below did not distinguish
+This policy determines whether the :command:`install(TARGETS)` command must be
+given a ``BUNDLE DESTINATION`` when asked to install a target with the
+:prop_tgt:`MACOSX_BUNDLE` property set. CMake 2.4 and below did not distinguish
application bundles from normal executables when installing targets.
-CMake 2.6 provides a BUNDLE option to the install(TARGETS) command
-that specifies rules specific to application bundles on the Mac.
+CMake 2.6 provides a ``BUNDLE`` option to the :command:`install(TARGETS)`
+command that specifies rules specific to application bundles on the Mac.
Projects should use this option when installing a target with the
-MACOSX_BUNDLE property set.
+:prop_tgt:`MACOSX_BUNDLE` property set.
-The OLD behavior for this policy is to fall back to the RUNTIME
-DESTINATION if a BUNDLE DESTINATION is not given. The NEW behavior
-for this policy is to produce an error if a bundle target is installed
-without a BUNDLE DESTINATION.
+The ``OLD`` behavior for this policy is to fall back to the
+``RUNTIME DESTINATION`` if a ``BUNDLE DESTINATION`` is not given. The ``NEW``
+behavior for this policy is to produce an error if a bundle target is installed
+without a ``BUNDLE DESTINATION``.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0007.rst b/Help/policy/CMP0007.rst
index 39276457a..1006ed33a 100644
--- a/Help/policy/CMP0007.rst
+++ b/Help/policy/CMP0007.rst
@@ -5,13 +5,13 @@ list command no longer ignores empty elements.
This policy determines whether the list command will ignore empty
elements in the list. CMake 2.4 and below list commands ignored all
-empty elements in the list. For example, a;b;;c would have length 3
-and not 4. The OLD behavior for this policy is to ignore empty list
-elements. The NEW behavior for this policy is to correctly count
+empty elements in the list. For example, ``a;b;;c`` would have length 3
+and not 4. The ``OLD`` behavior for this policy is to ignore empty list
+elements. The ``NEW`` behavior for this policy is to correctly count
empty elements in a list.
This policy was introduced in CMake version 2.6.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0008.rst b/Help/policy/CMP0008.rst
index f1e2ddde5..18ede821c 100644
--- a/Help/policy/CMP0008.rst
+++ b/Help/policy/CMP0008.rst
@@ -9,26 +9,27 @@ In CMake 2.4 and below it is possible to write code like
target_link_libraries(myexe /full/path/to/somelib)
-where "somelib" is supposed to be a valid library file name such as
-"libsomelib.a" or "somelib.lib". For Makefile generators this
+where ``somelib`` is supposed to be a valid library file name such as
+``libsomelib.a`` or ``somelib.lib``. For Makefile generators this
produces an error at build time because the dependency on the full
-path cannot be found. For VS IDE and Xcode generators this used to
+path cannot be found. For :ref:`Visual Studio Generators` IDE
+and :generator:`Xcode` generators this used to
work by accident because CMake would always split off the library
directory and ask the linker to search for the library by name
-(-lsomelib or somelib.lib). Despite the failure with Makefiles, some
-projects have code like this and build only with VS and/or Xcode.
+(``-lsomelib`` or ``somelib.lib``). Despite the failure with Makefiles, some
+projects have code like this and build only with Visual Studio and/or Xcode.
This version of CMake prefers to pass the full path directly to the
native build tool, which will fail in this case because it does not
name a valid library file.
This policy determines what to do with full paths that do not appear
-to name a valid library file. The OLD behavior for this policy is to
+to name a valid library file. The ``OLD`` behavior for this policy is to
split the library name from the path and ask the linker to search for
-it. The NEW behavior for this policy is to trust the given path and
+it. The ``NEW`` behavior for this policy is to trust the given path and
pass it directly to the native build tool unchanged.
This policy was introduced in CMake version 2.6.1. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0009.rst b/Help/policy/CMP0009.rst
index 44baeb449..27cfde0db 100644
--- a/Help/policy/CMP0009.rst
+++ b/Help/policy/CMP0009.rst
@@ -3,19 +3,19 @@ CMP0009
FILE GLOB_RECURSE calls should not follow symlinks by default.
-In CMake 2.6.1 and below, FILE GLOB_RECURSE calls would follow through
-symlinks, sometimes coming up with unexpectedly large result sets
+In CMake 2.6.1 and below, :command:`file(GLOB_RECURSE)` calls would follow
+through symlinks, sometimes coming up with unexpectedly large result sets
because of symlinks to top level directories that contain hundreds of
thousands of files.
This policy determines whether or not to follow symlinks encountered
-during a FILE GLOB_RECURSE call. The OLD behavior for this policy is
-to follow the symlinks. The NEW behavior for this policy is not to
-follow the symlinks by default, but only if FOLLOW_SYMLINKS is given
-as an additional argument to the FILE command.
+during a :command:`file(GLOB_RECURSE)` call. The ``OLD`` behavior for this
+policy is to follow the symlinks. The ``NEW`` behavior for this policy is not
+to follow the symlinks by default, but only if ``FOLLOW_SYMLINKS`` is given
+as an additional argument to the ``FILE`` command.
This policy was introduced in CMake version 2.6.2. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0010.rst b/Help/policy/CMP0010.rst
index 344d70475..cfae4982a 100644
--- a/Help/policy/CMP0010.rst
+++ b/Help/policy/CMP0010.rst
@@ -4,17 +4,17 @@ CMP0010
Bad variable reference syntax is an error.
In CMake 2.6.2 and below, incorrect variable reference syntax such as
-a missing close-brace ("${FOO") was reported but did not stop
+a missing close-brace (``${FOO``) was reported but did not stop
processing of CMake code. This policy determines whether a bad
-variable reference is an error. The OLD behavior for this policy is
+variable reference is an error. The ``OLD`` behavior for this policy is
to warn about the error, leave the string untouched, and continue.
-The NEW behavior for this policy is to report an error.
+The ``NEW`` behavior for this policy is to report an error.
If :policy:`CMP0053` is set to ``NEW``, this policy has no effect
and is treated as always being ``NEW``.
This policy was introduced in CMake version 2.6.3. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0011.rst b/Help/policy/CMP0011.rst
index d281e0ef7..257415c26 100644
--- a/Help/policy/CMP0011.rst
+++ b/Help/policy/CMP0011.rst
@@ -1,24 +1,25 @@
CMP0011
-------
-Included scripts do automatic cmake_policy PUSH and POP.
+Included scripts do automatic :command:`cmake_policy` PUSH and POP.
In CMake 2.6.2 and below, CMake Policy settings in scripts loaded by
-the include() and find_package() commands would affect the includer.
-Explicit invocations of cmake_policy(PUSH) and cmake_policy(POP) were
-required to isolate policy changes and protect the includer. While
-some scripts intend to affect the policies of their includer, most do
-not. In CMake 2.6.3 and above, include() and find_package() by
-default PUSH and POP an entry on the policy stack around an included
-script, but provide a NO_POLICY_SCOPE option to disable it. This
-policy determines whether or not to imply NO_POLICY_SCOPE for
-compatibility. The OLD behavior for this policy is to imply
-NO_POLICY_SCOPE for include() and find_package() commands. The NEW
-behavior for this policy is to allow the commands to do their default
-cmake_policy PUSH and POP.
+the :command:`include` and :command:`find_package` commands would affect
+the includer. Explicit invocations of ``cmake_policy(PUSH)`` and
+``cmake_policy(POP)`` were required to isolate policy changes and protect
+the includer. While some scripts intend to affect the policies of their
+includer, most do not. In CMake 2.6.3 and above, :command:`include` and
+:command:`find_package` by default ``PUSH`` and ``POP`` an entry on
+the policy stack around an included
+script, but provide a ``NO_POLICY_SCOPE`` option to disable it. This
+policy determines whether or not to imply ``NO_POLICY_SCOPE`` for
+compatibility. The ``OLD`` behavior for this policy is to imply
+``NO_POLICY_SCOPE`` for :command:`include` and :command:`find_package` commands.
+The ``NEW`` behavior for this policy is to allow the commands to do
+their default cmake_policy ``PUSH`` and ``POP``.
This policy was introduced in CMake version 2.6.3. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0012.rst b/Help/policy/CMP0012.rst
index 85d64f4d4..17ec8d33d 100644
--- a/Help/policy/CMP0012.rst
+++ b/Help/policy/CMP0012.rst
@@ -1,27 +1,28 @@
CMP0012
-------
-if() recognizes numbers and boolean constants.
+:command:`if` recognizes numbers and boolean constants.
-In CMake versions 2.6.4 and lower the if() command implicitly
+In CMake versions 2.6.4 and lower the :command:`if` command implicitly
dereferenced arguments corresponding to variables, even those named
-like numbers or boolean constants, except for 0 and 1. Numbers and
-boolean constants such as true, false, yes, no, on, off, y, n,
-notfound, ignore (all case insensitive) were recognized in some cases
-but not all. For example, the code "if(TRUE)" might have evaluated as
-false. Numbers such as 2 were recognized only in boolean expressions
-like "if(NOT 2)" (leading to false) but not as a single-argument like
-"if(2)" (also leading to false). Later versions of CMake prefer to
+like numbers or boolean constants, except for ``0`` and ``1``. Numbers and
+boolean constants such as ``true``, ``false``, ``yes``, ``no``, ``on``,
+``off``, ``y``, ``n``, ``notfound``, ``ignore`` (all case insensitive)
+were recognized in some cases but not all. For example, the code ``if(TRUE)``
+might have evaluated as ``false``.
+Numbers such as 2 were recognized only in boolean expressions
+like ``if(NOT 2)`` (leading to ``false``) but not as a single-argument like
+``if(2)`` (also leading to ``false``). Later versions of CMake prefer to
treat numbers and boolean constants literally, so they should not be
used as variable names.
-The OLD behavior for this policy is to implicitly dereference
-variables named like numbers and boolean constants. The NEW behavior
+The ``OLD`` behavior for this policy is to implicitly dereference
+variables named like numbers and boolean constants. The ``NEW`` behavior
for this policy is to recognize numbers and boolean constants without
dereferencing variables with such names.
This policy was introduced in CMake version 2.8.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0013.rst b/Help/policy/CMP0013.rst
index 2fabb8920..dbd67a177 100644
--- a/Help/policy/CMP0013.rst
+++ b/Help/policy/CMP0013.rst
@@ -9,13 +9,13 @@ generation files would be written and then overwritten in the build
tree and could lead to strange behavior. CMake 2.6.4 and above
explicitly detect duplicate binary directories. CMake 2.6.4 always
considers this case an error. In CMake 2.8.0 and above this policy
-determines whether or not the case is an error. The OLD behavior for
+determines whether or not the case is an error. The ``OLD`` behavior for
this policy is to allow duplicate binary directories. The NEW
behavior for this policy is to disallow duplicate binary directories
with an error.
This policy was introduced in CMake version 2.8.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0014.rst b/Help/policy/CMP0014.rst
index f1f7b77b8..331dde5ef 100644
--- a/Help/policy/CMP0014.rst
+++ b/Help/policy/CMP0014.rst
@@ -1,17 +1,17 @@
CMP0014
-------
-Input directories must have CMakeLists.txt.
+Input directories must have ``CMakeLists.txt``.
-CMake versions before 2.8 silently ignored missing CMakeLists.txt
-files in directories referenced by add_subdirectory() or subdirs(),
+CMake versions before 2.8 silently ignored missing ``CMakeLists.txt``
+files in directories referenced by :command:`add_subdirectory` or :command:`subdirs`,
treating them as if present but empty. In CMake 2.8.0 and above this
-policy determines whether or not the case is an error. The OLD
-behavior for this policy is to silently ignore the problem. The NEW
-behavior for this policy is to report an error.
+:command:`cmake_policy` determines whether or not the case is an error.
+The ``OLD`` behavior for this policy is to silently ignore the problem.
+The ``NEW`` behavior for this policy is to report an error.
This policy was introduced in CMake version 2.8.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0015.rst b/Help/policy/CMP0015.rst
index 9a48e3dac..90d520334 100644
--- a/Help/policy/CMP0015.rst
+++ b/Help/policy/CMP0015.rst
@@ -1,19 +1,19 @@
CMP0015
-------
-link_directories() treats paths relative to the source dir.
+ :command:`link_directories` treats paths relative to the source dir.
-In CMake 2.8.0 and lower the link_directories() command passed
+In CMake 2.8.0 and lower the :command:`link_directories` command passed
relative paths unchanged to the linker. In CMake 2.8.1 and above the
-link_directories() command prefers to interpret relative paths with
-respect to CMAKE_CURRENT_SOURCE_DIR, which is consistent with
-include_directories() and other commands. The OLD behavior for this
-policy is to use relative paths verbatim in the linker command. The
-NEW behavior for this policy is to convert relative paths to absolute
-paths by appending the relative path to CMAKE_CURRENT_SOURCE_DIR.
+:command:`link_directories` command prefers to interpret relative paths with
+respect to ``CMAKE_CURRENT_SOURCE_DIR``, which is consistent with
+:command:`include_directories` and other commands. The ``OLD`` behavior for
+this policy is to use relative paths verbatim in the linker command. The
+``NEW`` behavior for this policy is to convert relative paths to absolute
+paths by appending the relative path to ``CMAKE_CURRENT_SOURCE_DIR``.
This policy was introduced in CMake version 2.8.1. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0016.rst b/Help/policy/CMP0016.rst
index cc898c8ca..026d02a9d 100644
--- a/Help/policy/CMP0016.rst
+++ b/Help/policy/CMP0016.rst
@@ -1,15 +1,16 @@
CMP0016
-------
-target_link_libraries() reports error if its only argument is not a target.
+:command:`target_link_libraries` reports error if its only argument
+is not a target.
-In CMake 2.8.2 and lower the target_link_libraries() command silently
+In CMake 2.8.2 and lower the :command:`target_link_libraries` command silently
ignored if it was called with only one argument, and this argument
wasn't a valid target. In CMake 2.8.3 and above it reports an error
in this case.
This policy was introduced in CMake version 2.8.3. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0017.rst b/Help/policy/CMP0017.rst
index 9f0f0380f..ca4664eed 100644
--- a/Help/policy/CMP0017.rst
+++ b/Help/policy/CMP0017.rst
@@ -4,18 +4,18 @@ CMP0017
Prefer files from the CMake module directory when including from there.
Starting with CMake 2.8.4, if a cmake-module shipped with CMake (i.e.
-located in the CMake module directory) calls include() or
-find_package(), the files located in the CMake module directory are
-preferred over the files in CMAKE_MODULE_PATH. This makes sure that
-the modules belonging to CMake always get those files included which
+located in the CMake module directory) calls :command:`include` or
+:command:`find_package`, the files located in the CMake module directory are
+preferred over the files in :variable:`CMAKE_MODULE_PATH`. This makes sure
+that the modules belonging to CMake always get those files included which
they expect, and against which they were developed and tested. In all
-other cases, the files found in CMAKE_MODULE_PATH still take
-precedence over the ones in the CMake module directory. The OLD
+other cases, the files found in :variable:`CMAKE_MODULE_PATH` still take
+precedence over the ones in the CMake module directory. The ``OLD``
behavior is to always prefer files from CMAKE_MODULE_PATH over files
from the CMake modules directory.
This policy was introduced in CMake version 2.8.4. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0018.rst b/Help/policy/CMP0018.rst
index a3a7a12bd..624840678 100644
--- a/Help/policy/CMP0018.rst
+++ b/Help/policy/CMP0018.rst
@@ -1,34 +1,35 @@
CMP0018
-------
-Ignore CMAKE_SHARED_LIBRARY_<Lang>_FLAGS variable.
+Ignore ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` variable.
-CMake 2.8.8 and lower compiled sources in SHARED and MODULE libraries
-using the value of the undocumented CMAKE_SHARED_LIBRARY_<Lang>_FLAGS
+CMake 2.8.8 and lower compiled sources in ``SHARED`` and ``MODULE`` libraries
+using the value of the undocumented ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS``
platform variable. The variable contained platform-specific flags
needed to compile objects for shared libraries. Typically it included
-a flag such as -fPIC for position independent code but also included
+a flag such as ``-fPIC`` for position independent code but also included
other flags needed on certain platforms. CMake 2.8.9 and higher
-prefer instead to use the POSITION_INDEPENDENT_CODE target property to
-determine what targets should be position independent, and new
+prefer instead to use the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
+property to determine what targets should be position independent, and new
undocumented platform variables to select flags while ignoring
-CMAKE_SHARED_LIBRARY_<Lang>_FLAGS completely.
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` completely.
The default for either approach produces identical compilation flags,
-but if a project modifies CMAKE_SHARED_LIBRARY_<Lang>_FLAGS from its
+but if a project modifies ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` from its
original value this policy determines which approach to use.
-The OLD behavior for this policy is to ignore the
-POSITION_INDEPENDENT_CODE property for all targets and use the
-modified value of CMAKE_SHARED_LIBRARY_<Lang>_FLAGS for SHARED and
-MODULE libraries.
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property for all targets and use the
+modified value of ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` for ``SHARED`` and
+``MODULE`` libraries.
-The NEW behavior for this policy is to ignore
-CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and
-honor the POSITION_INDEPENDENT_CODE target property.
+The ``NEW`` behavior for this policy is to ignore
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` whether it is modified or not and
+honor the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property.
This policy was introduced in CMake version 2.8.9. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0019.rst b/Help/policy/CMP0019.rst
index 2e3557d32..682dcdf86 100644
--- a/Help/policy/CMP0019.rst
+++ b/Help/policy/CMP0019.rst
@@ -11,12 +11,12 @@ CMake versions because all variable references are now normally
evaluated during CMake language processing. CMake 2.8.11 and higher
prefer to skip the extra evaluation.
-The OLD behavior for this policy is to re-evaluate the values for
-strict compatibility. The NEW behavior for this policy is to leave
+The ``OLD`` behavior for this policy is to re-evaluate the values for
+strict compatibility. The ``NEW`` behavior for this policy is to leave
the values untouched.
This policy was introduced in CMake version 2.8.11. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0020.rst b/Help/policy/CMP0020.rst
index 75ca9deb2..6d27684f2 100644
--- a/Help/policy/CMP0020.rst
+++ b/Help/policy/CMP0020.rst
@@ -1,27 +1,27 @@
CMP0020
-------
-Automatically link Qt executables to qtmain target on Windows.
+Automatically link Qt executables to ``qtmain`` target on Windows.
CMake 2.8.10 and lower required users of Qt to always specify a link
-dependency to the qtmain.lib static library manually on Windows.
+dependency to the ``qtmain.lib`` static library manually on Windows.
CMake 2.8.11 gained the ability to evaluate generator expressions
-while determining the link dependencies from IMPORTED targets. This
+while determining the link dependencies from ``IMPORTED`` targets. This
allows CMake itself to automatically link executables which link to Qt
-to the qtmain.lib library when using IMPORTED Qt targets. For
-applications already linking to qtmain.lib, this should have little
+to the ``qtmain.lib`` library when using ``IMPORTED`` Qt targets. For
+applications already linking to ``qtmain.lib``, this should have little
impact. For applications which supply their own alternative WinMain
implementation and for applications which use the QAxServer library,
this automatic linking will need to be disabled as per the
documentation.
-The OLD behavior for this policy is not to link executables to
-qtmain.lib automatically when they link to the QtCore IMPORTED target.
-The NEW behavior for this policy is to link executables to qtmain.lib
-automatically when they link to QtCore IMPORTED target.
+The ``OLD`` behavior for this policy is not to link executables to
+``qtmain.lib`` automatically when they link to the QtCore ``IMPORTED`` target.
+The ``NEW`` behavior for this policy is to link executables to ``qtmain.lib``
+automatically when they link to QtCore ``IMPORTED`` target.
This policy was introduced in CMake version 2.8.11. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0021.rst b/Help/policy/CMP0021.rst
index 3a792ca14..937b106eb 100644
--- a/Help/policy/CMP0021.rst
+++ b/Help/policy/CMP0021.rst
@@ -1,20 +1,21 @@
CMP0021
-------
-Fatal error on relative paths in INCLUDE_DIRECTORIES target property.
+Fatal error on relative paths in :prop_tgt:`INCLUDE_DIRECTORIES` target
+property.
-CMake 2.8.10.2 and lower allowed the INCLUDE_DIRECTORIES target
+CMake 2.8.10.2 and lower allowed the :prop_tgt:`INCLUDE_DIRECTORIES` target
property to contain relative paths. The base path for such relative
-entries is not well defined. CMake 2.8.12 issues a FATAL_ERROR if the
-INCLUDE_DIRECTORIES property contains a relative path.
+entries is not well defined. CMake 2.8.12 issues a ``FATAL_ERROR`` if the
+:prop_tgt:`INCLUDE_DIRECTORIES` property contains a relative path.
-The OLD behavior for this policy is not to warn about relative paths
-in the INCLUDE_DIRECTORIES target property. The NEW behavior for this
-policy is to issue a FATAL_ERROR if INCLUDE_DIRECTORIES contains a
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the ``INCLUDE_DIRECTORIES`` target property. The ``NEW`` behavior for this
+policy is to issue a ``FATAL_ERROR`` if ``INCLUDE_DIRECTORIES`` contains a
relative path.
This policy was introduced in CMake version 2.8.12. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0022.rst b/Help/policy/CMP0022.rst
index 579d09ac0..be60e375a 100644
--- a/Help/policy/CMP0022.rst
+++ b/Help/policy/CMP0022.rst
@@ -1,39 +1,39 @@
CMP0022
-------
-INTERFACE_LINK_LIBRARIES defines the link interface.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` defines the link interface.
CMake 2.8.11 constructed the 'link interface' of a target from
properties matching ``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
The modern way to specify config-sensitive content is to use generator
expressions and the ``IMPORTED_`` prefix makes uniform processing of the
link interface with generator expressions impossible. The
-INTERFACE_LINK_LIBRARIES target property was introduced as a
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property was introduced as a
replacement in CMake 2.8.12. This new property is named consistently
-with the INTERFACE_COMPILE_DEFINITIONS, INTERFACE_INCLUDE_DIRECTORIES
-and INTERFACE_COMPILE_OPTIONS properties. For in-build targets, CMake
+with the ``INTERFACE_COMPILE_DEFINITIONS``, ``INTERFACE_INCLUDE_DIRECTORIES``
+and ``INTERFACE_COMPILE_OPTIONS`` properties. For in-build targets, CMake
will use the INTERFACE_LINK_LIBRARIES property as the source of the
-link interface only if policy CMP0022 is NEW. When exporting a target
-which has this policy set to NEW, only the INTERFACE_LINK_LIBRARIES
-property will be processed and generated for the IMPORTED target by
-default. A new option to the install(EXPORT) and export commands
+link interface only if policy ``CMP0022`` is ``NEW``. When exporting a target
+which has this policy set to ``NEW``, only the :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+property will be processed and generated for the ``IMPORTED`` target by
+default. A new option to the :command:`install(EXPORT)` and export commands
allows export of the old-style properties for compatibility with
downstream users of CMake versions older than 2.8.12. The
-target_link_libraries command will no longer populate the properties
-matching LINK_INTERFACE_LIBRARIES(_<CONFIG>)? if this policy is NEW.
+:command:`target_link_libraries` command will no longer populate the properties
+matching ``LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` if this policy is ``NEW``.
Warning-free future-compatible code which works with CMake 2.8.7 onwards
can be written by using the ``LINK_PRIVATE`` and ``LINK_PUBLIC`` keywords
of :command:`target_link_libraries`.
-The OLD behavior for this policy is to ignore the
-INTERFACE_LINK_LIBRARIES property for in-build targets. The NEW
-behavior for this policy is to use the INTERFACE_LINK_LIBRARIES
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property for in-build targets.
+The ``NEW`` behavior for this policy is to use the ``INTERFACE_LINK_LIBRARIES``
property for in-build targets, and ignore the old properties matching
``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
This policy was introduced in CMake version 2.8.12. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0023.rst b/Help/policy/CMP0023.rst
index 76a4900b6..3c72c8195 100644
--- a/Help/policy/CMP0023.rst
+++ b/Help/policy/CMP0023.rst
@@ -1,15 +1,15 @@
CMP0023
-------
-Plain and keyword target_link_libraries signatures cannot be mixed.
+Plain and keyword :command:`target_link_libraries` signatures cannot be mixed.
-CMake 2.8.12 introduced the target_link_libraries signature using the
-PUBLIC, PRIVATE, and INTERFACE keywords to generalize the LINK_PUBLIC
-and LINK_PRIVATE keywords introduced in CMake 2.8.7. Use of
-signatures with any of these keywords sets the link interface of a
+CMake 2.8.12 introduced the :command:`target_link_libraries` signature using
+the ``PUBLIC``, ``PRIVATE``, and ``INTERFACE`` keywords to generalize the
+``LINK_PUBLIC`` and ``LINK_PRIVATE`` keywords introduced in CMake 2.8.7.
+Use of signatures with any of these keywords sets the link interface of a
target explicitly, even if empty. This produces confusing behavior
when used in combination with the historical behavior of the plain
-target_link_libraries signature. For example, consider the code:
+:command:`target_link_libraries` signature. For example, consider the code:
::
@@ -20,16 +20,16 @@ After the first line the link interface has not been set explicitly so
CMake would use the link implementation, A, as the link interface.
However, the second line sets the link interface to empty. In order
to avoid this subtle behavior CMake now prefers to disallow mixing the
-plain and keyword signatures of target_link_libraries for a single
+plain and keyword signatures of :command:`target_link_libraries` for a single
target.
-The OLD behavior for this policy is to allow keyword and plain
-target_link_libraries signatures to be mixed. The NEW behavior for
+The ``OLD`` behavior for this policy is to allow keyword and plain
+:command:`target_link_libraries` signatures to be mixed. The ``NEW`` behavior for
this policy is to not to allow mixing of the keyword and plain
signatures.
This policy was introduced in CMake version 2.8.12. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0024.rst b/Help/policy/CMP0024.rst
index 272a56c8d..6e24b0454 100644
--- a/Help/policy/CMP0024.rst
+++ b/Help/policy/CMP0024.rst
@@ -3,22 +3,23 @@ CMP0024
Disallow include export result.
-CMake 2.8.12 and lower allowed use of the include() command with the
-result of the export() command. This relies on the assumption that
-the export() command has an immediate effect at configure-time during
+CMake 2.8.12 and lower allowed use of the :command:`include` command with the
+result of the :command:`export` command. This relies on the assumption that
+the :command:`export` command has an immediate effect at configure-time during
a cmake run. Certain properties of targets are not fully determined
until later at generate-time, such as the link language and complete
list of link libraries. Future refactoring will change the effect of
-the export() command to be executed at generate-time. Use ALIAS
+the :command:`export` command to be executed at generate-time. Use ``ALIAS``
targets instead in cases where the goal is to refer to targets by
another name.
-The OLD behavior for this policy is to allow including the result of
-an export() command. The NEW behavior for this policy is not to
-allow including the result of an export() command.
+The ``OLD`` behavior for this policy is to allow including the result of
+an :command:`export` command. The ``NEW`` behavior for this policy is not to
+allow including the result of an :command:`export` command.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0025.rst b/Help/policy/CMP0025.rst
index 62dd50985..ba5e1e948 100644
--- a/Help/policy/CMP0025.rst
+++ b/Help/policy/CMP0025.rst
@@ -15,13 +15,13 @@ language ``<LANG>`` is enabled by the :command:`project` or
:command:`enable_language` command. The policy must be set prior
to the invocation of either command.
-The OLD behavior for this policy is to use compiler id ``Clang``. The
-NEW behavior for this policy is to use compiler id ``AppleClang``.
+The ``OLD`` behavior for this policy is to use compiler id ``Clang``. The
+``NEW`` behavior for this policy is to use compiler id ``AppleClang``.
This policy was introduced in CMake version 3.0. Use the
-:command:`cmake_policy` command to set this policy to OLD or NEW explicitly.
-Unlike most policies, CMake version |release| does *not* warn
-by default when this policy is not set and simply uses OLD behavior.
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly. Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0025 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0026.rst b/Help/policy/CMP0026.rst
index 3fe1374c8..3401d4a9a 100644
--- a/Help/policy/CMP0026.rst
+++ b/Help/policy/CMP0026.rst
@@ -3,26 +3,27 @@ CMP0026
Disallow use of the LOCATION property for build targets.
-CMake 2.8.12 and lower allowed reading the LOCATION target
+CMake 2.8.12 and lower allowed reading the :prop_tgt:`LOCATION` target
property (and configuration-specific variants) to
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
-expression can be used to determine the eventual LOCATION of a target
+generate-time. At generate time, the ``$<TARGET_FILE>`` generator
+expression can be used to determine the eventual :prop_tgt:`LOCATION` of a target
output.
-Code which reads the LOCATION target property can be ported to use the
-$<TARGET_FILE> generator expression together with the file(GENERATE)
-subcommand to generate a file containing the target location.
+Code which reads the :prop_tgt:`LOCATION` target property can be ported to
+use the ``$<TARGET_FILE>`` generator expression together with the
+:command:`file(GENERATE)` subcommand to generate a file containing
+the target location.
-The OLD behavior for this policy is to allow reading the LOCATION
-properties from build-targets. The NEW behavior for this policy is to
-not to allow reading the LOCATION properties from build-targets.
+The ``OLD`` behavior for this policy is to allow reading the :prop_tgt:`LOCATION`
+properties from build-targets. The ``NEW`` behavior for this policy is to
+not to allow reading the :prop_tgt:`LOCATION` properties from build-targets.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0027.rst b/Help/policy/CMP0027.rst
index 28913cee4..bf7b6a978 100644
--- a/Help/policy/CMP0027.rst
+++ b/Help/policy/CMP0027.rst
@@ -4,24 +4,24 @@ CMP0027
Conditionally linked imported targets with missing include directories.
CMake 2.8.11 introduced introduced the concept of
-INTERFACE_INCLUDE_DIRECTORIES, and a check at cmake time that the
-entries in the INTERFACE_INCLUDE_DIRECTORIES of an IMPORTED target
-actually exist. CMake 2.8.11 also introduced generator expression
-support in the target_link_libraries command. However, if an imported
-target is linked as a result of a generator expression evaluation, the
-entries in the INTERFACE_INCLUDE_DIRECTORIES of that target were not
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`, and a check at cmake time that the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of an ``IMPORTED``
+target actually exist. CMake 2.8.11 also introduced generator expression
+support in the :command:`target_link_libraries` command. However, if an
+imported target is linked as a result of a generator expression evaluation, the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of that target were not
checked for existence as they should be.
-The OLD behavior of this policy is to report a warning if an entry in
-the INTERFACE_INCLUDE_DIRECTORIES of a generator-expression
-conditionally linked IMPORTED target does not exist.
+The ``OLD`` behavior of this policy is to report a warning if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
-The NEW behavior of this policy is to report an error if an entry in
-the INTERFACE_INCLUDE_DIRECTORIES of a generator-expression
-conditionally linked IMPORTED target does not exist.
+The ``NEW`` behavior of this policy is to report an error if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0028.rst b/Help/policy/CMP0028.rst
index be57125d4..ab3822993 100644
--- a/Help/policy/CMP0028.rst
+++ b/Help/policy/CMP0028.rst
@@ -1,25 +1,25 @@
CMP0028
-------
-Double colon in target name means ALIAS or IMPORTED target.
+Double colon in target name means ``ALIAS`` or ``IMPORTED`` target.
CMake 2.8.12 and lower allowed the use of targets and files with double
-colons in target_link_libraries, with some buildsystem generators.
+colons in :command:`target_link_libraries`, with some buildsystem generators.
-The use of double-colons is a common pattern used to namespace IMPORTED
-targets and ALIAS targets. When computing the link dependencies of a target,
-the name of each dependency could either be a target, or a file on disk.
-Previously, if a target was not found with a matching name, the name was
-considered to refer to a file on disk. This can lead to confusing error
+The use of double-colons is a common pattern used to namespace ``IMPORTED``
+targets and ``ALIAS`` targets. When computing the link dependencies of
+a target, the name of each dependency could either be a target, or a file
+on disk. Previously, if a target was not found with a matching name, the name
+was considered to refer to a file on disk. This can lead to confusing error
messages if there is a typo in what should be a target name.
-The OLD behavior for this policy is to search for targets, then files on disk,
-even if the search term contains double-colons. The NEW behavior for this
-policy is to issue a FATAL_ERROR if a link dependency contains
-double-colons but is not an IMPORTED target or an ALIAS target.
+The ``OLD`` behavior for this policy is to search for targets, then files on
+disk, even if the search term contains double-colons. The ``NEW`` behavior
+for this policy is to issue a ``FATAL_ERROR`` if a link dependency contains
+double-colons but is not an ``IMPORTED`` target or an ``ALIAS`` target.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0037.rst b/Help/policy/CMP0037.rst
index d1afeb7c2..9895fb0b4 100644
--- a/Help/policy/CMP0037.rst
+++ b/Help/policy/CMP0037.rst
@@ -10,24 +10,25 @@ as :manual:`cmake-generator-expressions(7)` and some
diagnostics expect target names to match a restricted pattern.
Target names may contain upper and lower case letters, numbers, the underscore
-character (_), dot(.), plus(+) and minus(-). As a special case, ALIAS
-targets and IMPORTED targets may contain two consecutive colons.
+character (``_``), dot(``.``), plus(``+``) and minus(``-``).
+As a special case, ``ALIAS`` and ``IMPORTED`` targets may contain
+two consecutive colons.
Target names reserved by one or more CMake generators are not allowed.
-Among others these include "all", "clean", "help", and "install".
+Among others these include ``all``, ``clean``, ``help``, and ``install``.
-Target names associated with optional features, such as "test" and "package",
-may also be reserved. CMake 3.10 and below always reserve them. CMake 3.11
-and above reserve them only when the corresponding feature is enabled
-(e.g. by including the :module:`CTest` or :module:`CPack` modules).
+Target names associated with optional features, such as ``test`` and
+``package``, may also be reserved. CMake 3.10 and below always reserve them.
+CMake 3.11 and above reserve them only when the corresponding feature is
+enabled (e.g. by including the :module:`CTest` or :module:`CPack` modules).
-The OLD behavior for this policy is to allow creating targets with
+The ``OLD`` behavior for this policy is to allow creating targets with
reserved names or which do not match the validity pattern.
-The NEW behavior for this policy is to report an error
+The ``NEW`` behavior for this policy is to report an error
if an add_* command is used with an invalid target name.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0038.rst b/Help/policy/CMP0038.rst
index a306d90a9..7fb2209fa 100644
--- a/Help/policy/CMP0038.rst
+++ b/Help/policy/CMP0038.rst
@@ -7,12 +7,12 @@ CMake 2.8.12 and lower allowed a build target to link to itself directly with
a :command:`target_link_libraries` call. This is an indicator of a bug in
user code.
-The OLD behavior for this policy is to ignore targets which list themselves
-in their own link implementation. The NEW behavior for this policy is to
+The ``OLD`` behavior for this policy is to ignore targets which list themselves
+in their own link implementation. The ``NEW`` behavior for this policy is to
report an error if a target attempts to link to itself.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0039.rst b/Help/policy/CMP0039.rst
index 97d78ae2a..4b14e21ae 100644
--- a/Help/policy/CMP0039.rst
+++ b/Help/policy/CMP0039.rst
@@ -7,13 +7,13 @@ CMake 2.8.12 and lower allowed using utility targets in the left hand side
position of the :command:`target_link_libraries` command. This is an indicator
of a bug in user code.
-The OLD behavior for this policy is to ignore attempts to set the link
-libraries of utility targets. The NEW behavior for this policy is to
+The ``OLD`` behavior for this policy is to ignore attempts to set the link
+libraries of utility targets. The ``NEW`` behavior for this policy is to
report an error if an attempt is made to set the link libraries of a
utility target.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0041.rst b/Help/policy/CMP0041.rst
index f027d5de9..3b4df3601 100644
--- a/Help/policy/CMP0041.rst
+++ b/Help/policy/CMP0041.rst
@@ -15,13 +15,13 @@ As an additional diagnostic, the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` gener
on an :prop_tgt:`IMPORTED` target for the install location should not contain
paths in the source directory or the build directory.
-The OLD behavior for this policy is to ignore relative path entries if they
-contain a generator expression. The NEW behavior for this policy is to report
+The ``OLD`` behavior for this policy is to ignore relative path entries if they
+contain a generator expression. The ``NEW`` behavior for this policy is to report
an error if a generator expression appears in another location and the path is
relative.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0042.rst b/Help/policy/CMP0042.rst
index 31314b2cd..087756450 100644
--- a/Help/policy/CMP0042.rst
+++ b/Help/policy/CMP0042.rst
@@ -15,7 +15,7 @@ the :prop_tgt:`INSTALL_NAME_DIR` and :variable:`CMAKE_INSTALL_NAME_DIR`
variables.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0043.rst b/Help/policy/CMP0043.rst
index 9e427c377..05210ac6e 100644
--- a/Help/policy/CMP0043.rst
+++ b/Help/policy/CMP0043.rst
@@ -35,13 +35,13 @@ or via :command:`target_compile_definitions`:
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DIR_DEBUG_MODE>
)
-The OLD behavior for this policy is to consume the content of the suffixed
+The ``OLD`` behavior for this policy is to consume the content of the suffixed
:prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property when generating the
-compilation command. The NEW behavior for this policy is to ignore the content
+compilation command. The ``NEW`` behavior for this policy is to ignore the content
of the :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property .
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0044.rst b/Help/policy/CMP0044.rst
index 02afa9f1a..6a4d040b1 100644
--- a/Help/policy/CMP0044.rst
+++ b/Help/policy/CMP0044.rst
@@ -9,13 +9,13 @@ comparison of the :variable:`CMAKE_<LANG>_COMPILER_ID` with a test value. The
possible valid values are lowercase, but the comparison with the test value
was performed case-insensitively.
-The OLD behavior for this policy is to perform a case-insensitive comparison
-with the value in the ``<LANG>_COMPILER_ID`` expression. The NEW behavior
+The ``OLD`` behavior for this policy is to perform a case-insensitive comparison
+with the value in the ``<LANG>_COMPILER_ID`` expression. The ``NEW`` behavior
for this policy is to perform a case-sensitive comparison with the value in
the ``<LANG>_COMPILER_ID`` expression.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0045.rst b/Help/policy/CMP0045.rst
index c7e1a90f6..80e217b18 100644
--- a/Help/policy/CMP0045.rst
+++ b/Help/policy/CMP0045.rst
@@ -7,13 +7,13 @@ In CMake 2.8.12 and lower, the :command:`get_target_property` command accepted
a non-existent target argument without issuing any error or warning. The
result variable is set to a ``-NOTFOUND`` value.
-The OLD behavior for this policy is to issue no warning and set the result
-variable to a ``-NOTFOUND`` value. The NEW behavior
+The ``OLD`` behavior for this policy is to issue no warning and set the result
+variable to a ``-NOTFOUND`` value. The ``NEW`` behavior
for this policy is to issue a ``FATAL_ERROR`` if the command is called with a
non-existent target.
This policy was introduced in CMake version 3.0. CMake version
-|release| warns when the policy is not set and uses OLD behavior. Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|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/CMP0046.rst b/Help/policy/CMP0046.rst
index 576d1b1cc..bf785842c 100644
--- a/Help/policy/CMP0046.rst
+++ b/Help/policy/CMP0046.rst
@@ -6,14 +6,14 @@ Error on non-existent dependency in add_dependencies.
CMake 2.8.12 and lower silently ignored non-existent dependencies
listed in the :command:`add_dependencies` command.
-The OLD behavior for this policy is to silently ignore non-existent
-dependencies. The NEW behavior for this policy is to report an error
+The ``OLD`` behavior for this policy is to silently ignore non-existent
+dependencies. The ``NEW`` behavior for this policy is to report an error
if non-existent dependencies are listed in the :command:`add_dependencies`
command.
This policy was introduced in CMake version 3.0.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0047.rst b/Help/policy/CMP0047.rst
index 882dd7828..9588edd7a 100644
--- a/Help/policy/CMP0047.rst
+++ b/Help/policy/CMP0047.rst
@@ -15,14 +15,14 @@ language ``<LANG>`` is enabled by the :command:`project` or
:command:`enable_language` command. The policy must be set prior
to the invocation of either command.
-The OLD behavior for this policy is to use the ``GNU`` compiler id
-for the qcc and QCC compiler drivers. The NEW behavior for this policy
+The ``OLD`` behavior for this policy is to use the ``GNU`` compiler id
+for the qcc and QCC compiler drivers. The ``NEW`` behavior for this policy
is to use the ``QCC`` compiler id for those drivers.
This policy was introduced in CMake version 3.0. Use the
-:command:`cmake_policy` command to set this policy to OLD or NEW explicitly.
-Unlike most policies, CMake version |release| does *not* warn
-by default when this policy is not set and simply uses OLD behavior.
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly. Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0047 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0048.rst b/Help/policy/CMP0048.rst
index 0e7e60681..e63ec01a2 100644
--- a/Help/policy/CMP0048.rst
+++ b/Help/policy/CMP0048.rst
@@ -1,24 +1,24 @@
CMP0048
-------
-The :command:`project` command manages VERSION variables.
+The :command:`project` command manages ``VERSION`` variables.
CMake version 3.0 introduced the ``VERSION`` option of the :command:`project`
command to specify a project version as well as the name. In order to keep
:variable:`PROJECT_VERSION` and related variables consistent with variable
-:variable:`PROJECT_NAME` it is necessary to set the VERSION variables
+:variable:`PROJECT_NAME` it is necessary to set the ``VERSION`` variables
to the empty string when no ``VERSION`` is given to :command:`project`.
-However, this can change behavior for existing projects that set VERSION
+However, this can change behavior for existing projects that set ``VERSION``
variables themselves since :command:`project` may now clear them.
This policy controls the behavior for compatibility with such projects.
-The OLD behavior for this policy is to leave VERSION variables untouched.
-The NEW behavior for this policy is to set VERSION as documented by the
+The ``OLD`` behavior for this policy is to leave ``VERSION`` variables untouched.
+The ``NEW`` behavior for this policy is to set ``VERSION`` as documented by the
:command:`project` command.
This policy was introduced in CMake version 3.0.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0049.rst b/Help/policy/CMP0049.rst
index 291bf5752..49b20be17 100644
--- a/Help/policy/CMP0049.rst
+++ b/Help/policy/CMP0049.rst
@@ -13,13 +13,13 @@ when evaluating source file names::
This was undocumented behavior.
-The OLD behavior for this policy is to expand such variables when processing
-the target sources. The NEW behavior for this policy is to issue an error
+The ``OLD`` behavior for this policy is to expand such variables when processing
+the target sources. The ``NEW`` behavior for this policy is to issue an error
if such variables need to be expanded.
This policy was introduced in CMake version 3.0.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0050.rst b/Help/policy/CMP0050.rst
index 39e40b698..27e7b1d50 100644
--- a/Help/policy/CMP0050.rst
+++ b/Help/policy/CMP0050.rst
@@ -8,13 +8,13 @@ which specified an input to a command. This was undocumented behavior.
Modern use of CMake associates custom commands with their output, rather
than their input.
-The OLD behavior for this policy is to allow the use of
-:command:`add_custom_command` SOURCE signatures. The NEW behavior for this
+The ``OLD`` behavior for this policy is to allow the use of
+:command:`add_custom_command` SOURCE signatures. The ``NEW`` behavior for this
policy is to issue an error if such a signature is used.
This policy was introduced in CMake version 3.0.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0052.rst b/Help/policy/CMP0052.rst
index 0ea5ace77..ee2e6e8de 100644
--- a/Help/policy/CMP0052.rst
+++ b/Help/policy/CMP0052.rst
@@ -1,7 +1,8 @@
CMP0052
-------
-Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES.
+Reject source and build dirs in installed
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`.
CMake 3.0 and lower allowed subdirectories of the source directory or build
directory to be in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of
@@ -13,9 +14,9 @@ broken if either are removed after installation.
See :ref:`Include Directories and Usage Requirements` for more on
specifying include directories for targets.
-The OLD behavior for this policy is to export the content of the
+The ``OLD`` behavior for this policy is to export the content of the
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` with the source or binary
-directory. The NEW behavior for this
+directory. The ``NEW`` behavior for this
policy is to issue an error if such a directory is used.
This policy was introduced in CMake version 3.1.
diff --git a/Help/policy/CMP0055.rst b/Help/policy/CMP0055.rst
index b3df758fe..bc5ad086b 100644
--- a/Help/policy/CMP0055.rst
+++ b/Help/policy/CMP0055.rst
@@ -7,13 +7,13 @@ CMake 3.1 and lower allowed calls to the :command:`break` command
outside of a loop context and also ignored any given arguments.
This was undefined behavior.
-The OLD behavior for this policy is to allow :command:`break` to be placed
-outside of loop contexts and ignores any arguments. The NEW behavior for this
+The ``OLD`` behavior for this policy is to allow :command:`break` to be placed
+outside of loop contexts and ignores any arguments. The ``NEW`` behavior for this
policy is to issue an error if a misplaced break or any arguments are found.
This policy was introduced in CMake version 3.2.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0056.rst b/Help/policy/CMP0056.rst
index 3ba89d576..834da844f 100644
--- a/Help/policy/CMP0056.rst
+++ b/Help/policy/CMP0056.rst
@@ -14,9 +14,9 @@ the generated project. CMake 3.2 and above prefer to set it so that
linker flags are honored as well as compiler flags. This policy
provides compatibility with the pre-3.2 behavior.
-The OLD behavior for this policy is to not set the value of the
+The ``OLD`` behavior for this policy is to not set the value of the
:variable:`CMAKE_EXE_LINKER_FLAGS` variable in the generated test
-project. The NEW behavior for this policy is to set the value of
+project. The ``NEW`` behavior for this policy is to set the value of
the :variable:`CMAKE_EXE_LINKER_FLAGS` variable in the test project
to the same as it is in the calling project.
@@ -27,7 +27,7 @@ variable in the cache.
This policy was introduced in CMake version 3.2. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0056 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0060.rst b/Help/policy/CMP0060.rst
index 8611affac..98ac2cf69 100644
--- a/Help/policy/CMP0060.rst
+++ b/Help/policy/CMP0060.rst
@@ -51,14 +51,14 @@ and link libraries by full path even when they are in implicit link
directories. Policy ``CMP0060`` provides compatibility for existing
projects.
-The OLD behavior for this policy is to ask the linker to search for
+The ``OLD`` behavior for this policy is to ask the linker to search for
libraries whose full paths are known to be in implicit link directories.
-The NEW behavior for this policy is to link libraries by full path even
+The ``NEW`` behavior for this policy is to link libraries by full path even
if they are in implicit link directories.
This policy was introduced in CMake version 3.3. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0060 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0061.rst b/Help/policy/CMP0061.rst
index cb2ac2840..57e4161d0 100644
--- a/Help/policy/CMP0061.rst
+++ b/Help/policy/CMP0061.rst
@@ -21,6 +21,6 @@ add ``-i``.
This policy was introduced in CMake version 3.3. Unlike most policies,
CMake version |release| does *not* warn when this policy is not set and
-simply uses OLD behavior.
+simply uses ``OLD`` behavior.
.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0062.rst b/Help/policy/CMP0062.rst
index 9047fffbe..0db7aafd0 100644
--- a/Help/policy/CMP0062.rst
+++ b/Help/policy/CMP0062.rst
@@ -1,7 +1,7 @@
CMP0062
-------
-Disallow install() of export() result.
+Disallow :command:`install` of :command:`export` result.
The :command:`export()` command generates a file containing
:ref:`Imported Targets`, which is suitable for use from the build
diff --git a/Help/policy/CMP0065.rst b/Help/policy/CMP0065.rst
index 2ed775dee..b820aad51 100644
--- a/Help/policy/CMP0065.rst
+++ b/Help/policy/CMP0065.rst
@@ -20,7 +20,7 @@ property is set to ``True``.
This policy was introduced in CMake version 3.4. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0065 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0066.rst b/Help/policy/CMP0066.rst
index d1dcb0ec6..e110ae127 100644
--- a/Help/policy/CMP0066.rst
+++ b/Help/policy/CMP0066.rst
@@ -20,7 +20,7 @@ variabldes like :variable:`CMAKE_<LANG>_FLAGS_DEBUG`.
This policy was introduced in CMake version 3.7. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0066 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0067.rst b/Help/policy/CMP0067.rst
index e6dda8018..f802787ff 100644
--- a/Help/policy/CMP0067.rst
+++ b/Help/policy/CMP0067.rst
@@ -30,7 +30,7 @@ setting variables.
This policy was introduced in CMake version 3.8. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0067 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0071.rst b/Help/policy/CMP0071.rst
index ee33aa1c2..855ecf0e9 100644
--- a/Help/policy/CMP0071.rst
+++ b/Help/policy/CMP0071.rst
@@ -21,7 +21,7 @@ source files.
.. note::
- To silence the CMP0071 warning source files can be excluded from
+ To silence the ``CMP0071`` warning source files can be excluded from
:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` processing by setting the
source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC` or
:prop_sf:`SKIP_AUTOGEN`.
diff --git a/Help/policy/CMP0082.rst b/Help/policy/CMP0082.rst
index 8256444c8..d887616be 100644
--- a/Help/policy/CMP0082.rst
+++ b/Help/policy/CMP0082.rst
@@ -19,7 +19,7 @@ declared.
This policy was introduced in CMake version 3.14. Unlike most policies,
CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior. See documentation of the
+is not set and simply uses ``OLD`` behavior. See documentation of the
:variable:`CMAKE_POLICY_WARNING_CMP0082 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
diff --git a/Help/policy/CMP0089.rst b/Help/policy/CMP0089.rst
new file mode 100644
index 000000000..029de5534
--- /dev/null
+++ b/Help/policy/CMP0089.rst
@@ -0,0 +1,30 @@
+CMP0089
+-------
+
+Compiler id for IBM Clang-based XL compilers is now ``XLClang``.
+
+CMake 3.15 and above recognize that IBM's Clang-based XL compilers
+that define ``__ibmxl__`` are a new front-end distinct from ``xlc``
+with a different command line and set of capabilities.
+CMake now prefers to present this to projects by setting the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable to ``XLClang`` instead
+of ``XL``. However, existing projects may assume the compiler id for
+Clang-based XL is just ``XL`` as it was in CMake versions prior to 3.15.
+Therefore this policy determines for Clang-based XL compilers which
+compiler id to report in the :variable:`CMAKE_<LANG>_COMPILER_ID`
+variable after language ``<LANG>`` is enabled by the :command:`project`
+or :command:`enable_language` command. The policy must be set prior
+to the invocation of either command.
+
+The ``OLD`` behavior for this policy is to use compiler id ``XL``. The
+``NEW`` behavior for this policy is to use compiler id ``XLClang``.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0089 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0090.rst b/Help/policy/CMP0090.rst
new file mode 100644
index 000000000..720c17c2a
--- /dev/null
+++ b/Help/policy/CMP0090.rst
@@ -0,0 +1,27 @@
+CMP0090
+-------
+
+:command:`export(PACKAGE)` does not populate package registry by default.
+
+In CMake 3.14 and below the :command:`export(PACKAGE)` command populated the
+user package registry by default and users needed to set the
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` to disable it, e.g. in automated
+build and packaging environments. Since the user package registry is stored
+outside the build tree, this side effect should not be enabled by default.
+Therefore CMake 3.15 and above prefer that :command:`export(PACKAGE)` does
+nothing unless an explicit :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable
+is set to enable it. This policy provides compatibility with projects that
+have not been updated.
+
+The ``OLD`` behavior for this policy is for :command:`export(PACKAGE)` command
+to populate the user package registry unless
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` is enabled.
+The ``NEW`` behavior is for :command:`export(PACKAGE)` command to do nothing
+unless the :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` is enabled.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most 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/CMP0091.rst b/Help/policy/CMP0091.rst
new file mode 100644
index 000000000..5b7c4e3d9
--- /dev/null
+++ b/Help/policy/CMP0091.rst
@@ -0,0 +1,47 @@
+CMP0091
+-------
+
+MSVC runtime library flags are selected by an abstraction.
+
+Compilers targeting the MSVC ABI have flags to select the MSVC runtime library.
+Runtime library selection typically varies with build configuration because
+there is a separate runtime library for Debug builds.
+
+In CMake 3.14 and below, MSVC runtime library selection flags are added to
+the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
+automatically. This allows users to edit their cache entries to adjust the
+flags. However, the presence of such default flags is problematic for
+projects that want to choose a different runtime library programmatically.
+In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave the MSVC runtime library selection flags
+out of the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values and instead
+offer a first-class abstraction. The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+variable and :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property may be set to
+select the MSVC runtime library.
+
+This policy provides compatibility with projects that have not been updated
+to be aware of the abstraction. The policy setting takes effect as of the
+first :command:`project` or :command:`enable_language` command that enables
+a language whose compiler targets the MSVC ABI.
+
+.. note::
+
+ Once the policy has taken effect at the top of a project, that choice
+ must be used throughout the tree. In projects that have nested projects
+ in subdirectories, be sure to convert everything together.
+
+The ``OLD`` behavior for this policy is to place MSVC runtime library
+flags in the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache
+entries and ignore the :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` abstraction.
+The ``NEW`` behavior for this policy is to *not* place MSVC runtime
+library flags in the default cache entries and use the abstraction instead.
+
+This policy was introduced in CMake version 3.15. 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/CMP0092.rst b/Help/policy/CMP0092.rst
new file mode 100644
index 000000000..8d3a288ae
--- /dev/null
+++ b/Help/policy/CMP0092.rst
@@ -0,0 +1,38 @@
+CMP0092
+-------
+
+MSVC warning flags are not in :variable:`CMAKE_<LANG>_FLAGS` by default.
+
+When using MSVC-like compilers in CMake 3.14 and below, warning flags
+like ``/W3`` are added to :variable:`CMAKE_<LANG>_FLAGS` by default.
+This is problematic for projects that want to choose a different warning
+level programmatically. In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave out warning flags from the value of
+:variable:`CMAKE_<LANG>_FLAGS` by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of warning flags. The policy setting takes effect as of
+the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_<LANG>_FLAGS` for a given lanuage ``<LANG>``.
+
+.. 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 MSVC warning flags in the
+default :variable:`CMAKE_<LANG>_FLAGS` cache entries. The ``NEW`` behavior
+for this policy is to *not* place MSVC warning flags in the default cache
+entries.
+
+This policy was introduced in CMake version 3.15. 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/CMP0093.rst b/Help/policy/CMP0093.rst
new file mode 100644
index 000000000..0ffc493de
--- /dev/null
+++ b/Help/policy/CMP0093.rst
@@ -0,0 +1,24 @@
+CMP0093
+-------
+
+:module:`FindBoost` reports ``Boost_VERSION`` in ``x.y.z`` format.
+
+In CMake 3.14 and below the module would report the Boost version
+number as specified in the preprocessor definition ``BOOST_VERSION`` in
+the ``boost/version.hpp`` file. In CMake 3.15 and later it is preferred
+that the reported version number matches the ``x.y.z`` format reported
+by the CMake package shipped with Boost ``1.70.0`` and later. The macro
+value is still reported in the ``Boost_VERSION_MACRO`` variable.
+
+The ``OLD`` behavior for this policy is for :module:`FindBoost` to report
+``Boost_VERSION`` as specified in the preprocessor definition
+``BOOST_VERSION`` in ``boost/version.hpp``. The ``NEW`` behavior for this
+policy is for :module:`FindBoost` to report ``Boost_VERSION`` in
+``x.y.z`` format.
+
+This policy was introduced in CMake version 3.15. 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 the ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0094.rst b/Help/policy/CMP0094.rst
new file mode 100644
index 000000000..836f30f09
--- /dev/null
+++ b/Help/policy/CMP0094.rst
@@ -0,0 +1,22 @@
+CMP0094
+-------
+
+Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+use ``LOCATION`` for lookup strategy.
+
+Starting with CMake 3.15, Modules :module:`FindPython3`, :module:`FindPython2`
+and :module:`FindPython` set value ``LOCATION`` for, respectively, variables
+``Python3_FIND_STRATEGY``, ``Python2_FIND_STRATEGY`` and
+``Python_FIND_STRATEGY``. This policy provides compatibility with projects that
+expect the legacy behavior.
+
+The ``OLD`` behavior for this policy set value ``VERSION`` for variables
+``Python3_FIND_STRATEGY``, ``Python2_FIND_STRATEGY`` and
+``Python_FIND_STRATEGY``.
+
+This policy was introduced in CMake version 3.15. 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 the ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/DISALLOWED_COMMAND.txt b/Help/policy/DISALLOWED_COMMAND.txt
index 36280d2b6..6500bb0f3 100644
--- a/Help/policy/DISALLOWED_COMMAND.txt
+++ b/Help/policy/DISALLOWED_COMMAND.txt
@@ -1,9 +1,9 @@
CMake >= |disallowed_version| prefer that this command never be called.
-The OLD behavior for this policy is to allow the command to be called.
-The NEW behavior for this policy is to issue a FATAL_ERROR when the
+The ``OLD`` behavior for this policy is to allow the command to be called.
+The ``NEW`` behavior for this policy is to issue a ``FATAL_ERROR`` when the
command is called.
This policy was introduced in CMake version |disallowed_version|.
CMake version |release| warns when the policy is not set and uses
-OLD behavior. Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
diff --git a/Help/prop_cache/ADVANCED.rst b/Help/prop_cache/ADVANCED.rst
index a0a4f73bb..ec4de9d85 100644
--- a/Help/prop_cache/ADVANCED.rst
+++ b/Help/prop_cache/ADVANCED.rst
@@ -4,5 +4,5 @@ ADVANCED
True if entry should be hidden by default in GUIs.
This is a boolean value indicating whether the entry is considered
-interesting only for advanced configuration. The mark_as_advanced()
+interesting only for advanced configuration. The :command:`mark_as_advanced`
command modifies this property.
diff --git a/Help/prop_cache/STRINGS.rst b/Help/prop_cache/STRINGS.rst
index 2f8e32e3f..0e3c326d2 100644
--- a/Help/prop_cache/STRINGS.rst
+++ b/Help/prop_cache/STRINGS.rst
@@ -1,9 +1,9 @@
STRINGS
-------
-Enumerate possible STRING entry values for GUI selection.
+Enumerate possible ``STRING`` entry values for GUI selection.
-For cache entries with type STRING, this enumerates a set of values.
+For cache entries with type ``STRING``, this enumerates a set of values.
CMake GUIs may use this to provide a selection widget instead of a
generic string entry field. This is for convenience only. CMake does
not enforce that the value matches one of those listed.
diff --git a/Help/prop_cache/TYPE.rst b/Help/prop_cache/TYPE.rst
index eb75c2ab2..7ca859f68 100644
--- a/Help/prop_cache/TYPE.rst
+++ b/Help/prop_cache/TYPE.rst
@@ -5,7 +5,7 @@ Widget type for entry in GUIs.
Cache entry values are always strings, but CMake GUIs present widgets
to help users set values. The GUIs use this property as a hint to
-determine the widget type. Valid TYPE values are:
+determine the widget type. Valid ``TYPE`` values are:
::
@@ -17,5 +17,5 @@ determine the widget type. Valid TYPE values are:
STATIC = Value managed by CMake, do not change.
UNINITIALIZED = Type not yet specified.
-Generally the TYPE of a cache entry should be set by the command which
-creates it (set, option, find_library, etc.).
+Generally the ``TYPE`` of a cache entry should be set by the command which
+creates it ( :command:`set`, :command:`option`, :command:`find_library`, etc.).
diff --git a/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
new file mode 100644
index 000000000..051d22a81
--- /dev/null
+++ b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
@@ -0,0 +1,21 @@
+ADDITIONAL_CLEAN_FILES
+----------------------
+
+A :ref:`;-list <CMake Language Lists>` of files or directories that will be
+removed as a part of the global ``clean`` target. It is useful for
+specifying generated files or directories that are used by multiple targets
+or by CMake itself, or that are generated in ways which cannot be captured as
+outputs or byproducts of custom commands.
+
+If an additional clean file is specific to a single target only, then the
+:prop_tgt:`ADDITIONAL_CLEAN_FILES` target property would usually be a better
+choice than this directory property.
+
+Relative paths are allowed and are interpreted relative to the
+current binary directory.
+
+Contents of ``ADDITIONAL_CLEAN_FILES`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the :generator:`Ninja` and the Makefile
+generators. It is ignored by other generators.
diff --git a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
index e32eed3ed..b6f616099 100644
--- a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
+++ b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
@@ -1,7 +1,17 @@
ADDITIONAL_MAKE_CLEAN_FILES
---------------------------
-Additional files to clean during the make clean stage.
+.. deprecated:: 3.15
-A list of files that will be cleaned as a part of the "make clean"
-stage.
+ Use :prop_dir:`ADDITIONAL_CLEAN_FILES` instead.
+
+Additional files to remove during the clean stage.
+
+A :ref:`;-list <CMake Language Lists>` of files that will be removed as a
+part of the ``make clean`` target.
+
+Arguments to :prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the Makefile generators.
+It is ignored on other generators.
diff --git a/Help/prop_dir/EXCLUDE_FROM_ALL.rst b/Help/prop_dir/EXCLUDE_FROM_ALL.rst
index 8e3cca0c2..9d3192c1b 100644
--- a/Help/prop_dir/EXCLUDE_FROM_ALL.rst
+++ b/Help/prop_dir/EXCLUDE_FROM_ALL.rst
@@ -1,13 +1,15 @@
EXCLUDE_FROM_ALL
----------------
-Set this directory property to a true value on a subdirectory to exclude
-its targets from the "all" target of its ancestors. If excluded, running
-e.g. ``make`` in the parent directory will not build targets the
-subdirectory by default. This does not affect the "all" target of the
-subdirectory itself. Running e.g. ``make`` inside the subdirectory will
-still build its targets.
+Exclude the directory from the all target of its parent.
-If the :prop_tgt:`EXCLUDE_FROM_ALL` target property is set on a target
-then its value determines whether the target is included in the "all"
-target of this directory and its ancestors.
+A property on a directory that indicates if its targets are excluded
+from the default build target. If it is not, then with a Makefile for
+example typing make will cause the targets to be built. The same
+concept applies to the default build of other generators.
+
+Targets inherit the :prop_tgt:`EXCLUDE_FROM_ALL` property from the directory
+that they are created in. When a directory is excluded, all of its targets will
+have :prop_tgt:`EXCLUDE_FROM_ALL` set to ``TRUE``. After creating such a target
+you can change its :prop_tgt:`EXCLUDE_FROM_ALL` property to ``FALSE``. This
+will cause the target to be included in the default build target.
diff --git a/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
index 993f6200e..f5349763a 100644
--- a/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
+++ b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
@@ -1,15 +1,15 @@
IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
----------------------------------
-Specify #include line transforms for dependencies in a directory.
+Specify ``#include`` line transforms for dependencies in a directory.
-This property specifies rules to transform macro-like #include lines
+This property specifies rules to transform macro-like ``#include`` lines
during implicit dependency scanning of C and C++ source files. The
list of rules must be semicolon-separated with each entry of the form
-"A_MACRO(%)=value-with-%" (the % must be literal). During dependency
-scanning occurrences of A_MACRO(...) on #include lines will be
+``A_MACRO(%)=value-with-%`` (the ``%`` must be literal). During dependency
+scanning occurrences of ``A_MACRO(...)`` on ``#include`` lines will be
replaced by the value given with the macro argument substituted for
-'%'. For example, the entry
+``%``. For example, the entry
::
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 325208656..840a1dbc7 100644
--- a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -3,6 +3,6 @@ INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
Per-configuration interprocedural optimization for a directory.
-This is a per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
+This is a per-configuration version of ``INTERPROCEDURAL_OPTIMIZATION``.
If set, this property overrides the generic property for the named
configuration.
diff --git a/Help/prop_dir/MACROS.rst b/Help/prop_dir/MACROS.rst
index e4feadaa5..245cc1b91 100644
--- a/Help/prop_dir/MACROS.rst
+++ b/Help/prop_dir/MACROS.rst
@@ -4,5 +4,5 @@ MACROS
List of macro commands available in the current directory.
This read-only property specifies the list of CMake macros currently
-defined. It is intended for debugging purposes. See the macro
+defined. It is intended for debugging purposes. See the :command:`macro`
command.
diff --git a/Help/prop_dir/TESTS.rst b/Help/prop_dir/TESTS.rst
index 56e230eb7..1c9f6e5c6 100644
--- a/Help/prop_dir/TESTS.rst
+++ b/Help/prop_dir/TESTS.rst
@@ -3,5 +3,6 @@ TESTS
List of tests.
-This read-only property holds a :ref:`semicolon-separated list <CMake Language Lists>` of tests
+This read-only property holds a
+:ref:`semicolon-separated list <CMake Language Lists>` of tests
defined so far, in the current directory, by the :command:`add_test` command.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
index 814bd5fe1..b65db99f3 100644
--- a/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
@@ -12,20 +12,20 @@ in the solution file:
<contents based on property value>
EndGlobalSection
-The property must be set to a semicolon-separated list of key=value
+The property must be set to a semicolon-separated list of ``key=value``
pairs. Each such pair will be transformed into an entry in the
solution global section. Whitespace around key and value is ignored.
List elements which do not contain an equal sign are skipped.
This property only works for Visual Studio 9 and above; it is ignored
on other generators. The property only applies when set on a
-directory whose CMakeLists.txt contains a project() command.
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
-Note that CMake generates postSolution sections ExtensibilityGlobals
-and ExtensibilityAddIns by default. If you set the corresponding
+Note that CMake generates postSolution sections ``ExtensibilityGlobals``
+and ``ExtensibilityAddIns`` by default. If you set the corresponding
property, it will override the default section. For example, setting
-VS_GLOBAL_SECTION_POST_ExtensibilityGlobals will override the default
-contents of the ExtensibilityGlobals section, while keeping
+``VS_GLOBAL_SECTION_POST_ExtensibilityGlobals`` will override the default
+contents of the ``ExtensibilityGlobals`` section, while keeping
ExtensibilityAddIns on its default. However, CMake will always
add a ``SolutionGuid`` to the ``ExtensibilityGlobals`` section
if it is not specified explicitly.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
index f70e9f176..7f8bf6161 100644
--- a/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
@@ -12,11 +12,11 @@ in the solution file:
<contents based on property value>
EndGlobalSection
-The property must be set to a semicolon-separated list of key=value
+The property must be set to a semicolon-separated list of ``key=value``
pairs. Each such pair will be transformed into an entry in the
solution global section. Whitespace around key and value is ignored.
List elements which do not contain an equal sign are skipped.
This property only works for Visual Studio 9 and above; it is ignored
on other generators. The property only applies when set on a
-directory whose CMakeLists.txt contains a project() command.
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
diff --git a/Help/prop_dir/VS_STARTUP_PROJECT.rst b/Help/prop_dir/VS_STARTUP_PROJECT.rst
index 04441b621..2680dfa6c 100644
--- a/Help/prop_dir/VS_STARTUP_PROJECT.rst
+++ b/Help/prop_dir/VS_STARTUP_PROJECT.rst
@@ -7,7 +7,7 @@ The :ref:`Visual Studio Generators` create a ``.sln`` file for each directory
whose ``CMakeLists.txt`` file calls the :command:`project` command. Set this
property in the same directory as a :command:`project` command call (e.g. in
the top-level ``CMakeLists.txt`` file) to specify the default startup project
-for the correpsonding solution file.
+for the corresponding solution file.
The property must be set to the name of an existing target. This
will cause that project to be listed first in the generated solution
diff --git a/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
index 8fab50345..19775ff2d 100644
--- a/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
+++ b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
@@ -4,16 +4,18 @@ ALLOW_DUPLICATE_CUSTOM_TARGETS
Allow duplicate custom targets to be created.
Normally CMake requires that all targets built in a project have
-globally unique logical names (see policy CMP0002). This is necessary
-to generate meaningful project file names in Xcode and VS IDE
+globally unique logical names (see policy :policy:`CMP0002`).
+This is necessary to generate meaningful project file names in
+:generator:`Xcode` and :ref:`Visual Studio Generators` IDE
generators. It also allows the target names to be referenced
unambiguously.
-Makefile generators are capable of supporting duplicate custom target
-names. For projects that care only about Makefile generators and do
-not wish to support Xcode or VS IDE generators, one may set this
-property to true to allow duplicate custom targets. The property
-allows multiple add_custom_target command calls in different
+Makefile generators are capable of supporting duplicate :command:`add_custom_target`
+names. For projects that care only about :ref:`Makefile Generators` and do
+not wish to support :generator:`Xcode` or :ref:`Visual Studio Generators` IDE
+generators, one may set this property to ``True``
+to allow duplicate custom targets. The property
+allows multiple :command:`add_custom_target` command calls in different
directories to specify the same target name. However, setting this
property will cause non-Makefile generators to produce an error and
refuse to generate the project.
diff --git a/Help/prop_gbl/DISABLED_FEATURES.rst b/Help/prop_gbl/DISABLED_FEATURES.rst
index 111cdf67e..882bbfacd 100644
--- a/Help/prop_gbl/DISABLED_FEATURES.rst
+++ b/Help/prop_gbl/DISABLED_FEATURES.rst
@@ -5,7 +5,7 @@ List of features which are disabled during the CMake run.
List of features which are disabled during the CMake run. By default
it contains the names of all packages which were not found. This is
-determined using the <NAME>_FOUND variables. Packages which are
-searched QUIET are not listed. A project can add its own features to
+determined using the ``<NAME>_FOUND`` variables. Packages which are
+searched ``QUIET`` are not listed. A project can add its own features to
this list. This property is used by the macros in
-FeatureSummary.cmake.
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/ENABLED_FEATURES.rst b/Help/prop_gbl/ENABLED_FEATURES.rst
index b03da5a45..acbb3d018 100644
--- a/Help/prop_gbl/ENABLED_FEATURES.rst
+++ b/Help/prop_gbl/ENABLED_FEATURES.rst
@@ -5,7 +5,7 @@ List of features which are enabled during the CMake run.
List of features which are enabled during the CMake run. By default
it contains the names of all packages which were found. This is
-determined using the <NAME>_FOUND variables. Packages which are
-searched QUIET are not listed. A project can add its own features to
+determined using the ``<NAME>_FOUND`` variables. Packages which are
+searched ``QUIET`` are not listed. A project can add its own features to
this list. This property is used by the macros in
-FeatureSummary.cmake.
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/JOB_POOLS.rst b/Help/prop_gbl/JOB_POOLS.rst
index b904f7a79..21da4662d 100644
--- a/Help/prop_gbl/JOB_POOLS.rst
+++ b/Help/prop_gbl/JOB_POOLS.rst
@@ -18,6 +18,11 @@ Defined pools could be used globally by setting
:variable:`CMAKE_JOB_POOL_COMPILE` and :variable:`CMAKE_JOB_POOL_LINK`
or per target by setting the target properties
:prop_tgt:`JOB_POOL_COMPILE` and :prop_tgt:`JOB_POOL_LINK`.
+:command:`Custom commands <add_custom_command>` and
+:command:`custom targets <add_custom_target>` can specify pools using the
+option ``JOB_POOL``.
+Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+an error by ninja at build time.
If not set, this property uses the value of the :variable:`CMAKE_JOB_POOLS`
variable.
diff --git a/Help/prop_gbl/USE_FOLDERS.rst b/Help/prop_gbl/USE_FOLDERS.rst
index a1b4ccb5b..591972327 100644
--- a/Help/prop_gbl/USE_FOLDERS.rst
+++ b/Help/prop_gbl/USE_FOLDERS.rst
@@ -4,7 +4,7 @@ USE_FOLDERS
Use the :prop_tgt:`FOLDER` target property to organize targets into
folders.
-If not set, CMake treats this property as OFF by default. CMake
+If not set, CMake treats this property as ``OFF`` by default. CMake
generators that are capable of organizing into a hierarchy of folders
use the values of the :prop_tgt:`FOLDER` target property to name those
-folders. See also the documentation for the FOLDER target property.
+folders. See also the documentation for the :prop_tgt:`FOLDER` target property.
diff --git a/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
index 9a6086ed8..950044301 100644
--- a/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
+++ b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
@@ -1,14 +1,15 @@
XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
----------------------------------
-Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the Xcode generator.
+Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the :generator:`Xcode`
+generator.
It is required for building the same target with multiple SDKs. A
common use case is the parallel use of ``iphoneos`` and
``iphonesimulator`` SDKs.
-Three different states possible that control when the Xcode generator
-emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
+Three different states possible that control when the :generator:`Xcode`
+generator emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
- If set to ``ON`` it will always be emitted
- If set to ``OFF`` it will never be emitted
diff --git a/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
index 11f2c036c..729ab603c 100644
--- a/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
@@ -1,7 +1,7 @@
CPACK_DESKTOP_SHORTCUTS
-----------------------
-Species a list of shortcut names that should be created on the Desktop
+Species a list of shortcut names that should be created on the `Desktop`
for this file.
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
index 11f44d0df..4789e253d 100644
--- a/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
+++ b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
@@ -3,4 +3,4 @@ CPACK_NEVER_OVERWRITE
Request that this file not be overwritten on install or reinstall.
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_PERMANENT.rst b/Help/prop_inst/CPACK_PERMANENT.rst
index 5e191d08e..985de0da9 100644
--- a/Help/prop_inst/CPACK_PERMANENT.rst
+++ b/Help/prop_inst/CPACK_PERMANENT.rst
@@ -3,4 +3,4 @@ CPACK_PERMANENT
Request that this file not be removed on uninstall.
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
index 8a160223d..d9208b9f9 100644
--- a/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
@@ -1,7 +1,7 @@
CPACK_STARTUP_SHORTCUTS
-----------------------
-Species a list of shortcut names that should be created in the Startup folder
+Species a list of shortcut names that should be created in the `Startup` folder
for this file.
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
index d30ea39fd..092334a5a 100644
--- a/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
@@ -1,7 +1,7 @@
CPACK_START_MENU_SHORTCUTS
--------------------------
-Species a list of shortcut names that should be created in the Start Menu
+Species a list of shortcut names that should be created in the `Start Menu`
for this file.
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_WIX_ACL.rst b/Help/prop_inst/CPACK_WIX_ACL.rst
index 4e13ec48c..c88f42675 100644
--- a/Help/prop_inst/CPACK_WIX_ACL.rst
+++ b/Help/prop_inst/CPACK_WIX_ACL.rst
@@ -17,3 +17,5 @@ each of which has to match the following format.
``<permission>`` is any of the YesNoType attributes listed here::
http://wixtoolset.org/documentation/manual/v3/xsd/wix/permission.html
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS.rst b/Help/prop_sf/COMPILE_DEFINITIONS.rst
index 8d2108c48..63176901e 100644
--- a/Help/prop_sf/COMPILE_DEFINITIONS.rst
+++ b/Help/prop_sf/COMPILE_DEFINITIONS.rst
@@ -3,14 +3,14 @@ COMPILE_DEFINITIONS
Preprocessor definitions for compiling a source file.
-The COMPILE_DEFINITIONS property may be set to a semicolon-separated
-list of preprocessor definitions using the syntax VAR or VAR=value.
+The ``COMPILE_DEFINITIONS`` property may be set to a semicolon-separated
+list of preprocessor definitions using the syntax ``VAR`` or ``VAR=value``.
Function-style definitions are not supported. CMake will
automatically escape the value correctly for the native build system
(note that CMake language syntax may require escapes to specify some
values). This property may be set on a per-configuration basis using
-the name COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case
-name (ex. "COMPILE_DEFINITIONS_DEBUG").
+the name ``COMPILE_DEFINITIONS_<CONFIG>`` where ``<CONFIG>`` is an upper-case
+name (ex. ``COMPILE_DEFINITIONS_DEBUG``).
CMake will automatically drop some definitions that are not supported
by the native build tool. Xcode does not support per-configuration
@@ -18,7 +18,7 @@ definitions on source files.
.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
-Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions"
+Contents of ``COMPILE_DEFINITIONS`` may use :manual:`cmake-generator-expressions(7)`
with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. However, :generator:`Xcode`
does not support per-config per-source settings, so expressions
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
index 848707647..ec867b65d 100644
--- a/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
+++ b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
@@ -5,6 +5,6 @@ Ignored. See CMake Policy :policy:`CMP0043`.
Per-configuration preprocessor definitions on a source file.
-This is the configuration-specific version of COMPILE_DEFINITIONS.
-Note that Xcode does not support per-configuration source file flags
-so this property will be ignored by the Xcode generator.
+This is the configuration-specific version of :prop_tgt:`COMPILE_DEFINITIONS`.
+Note that :generator:`Xcode` does not support per-configuration source
+file flags so this property will be ignored by the :generator:`Xcode` generator.
diff --git a/Help/prop_sf/EXTERNAL_OBJECT.rst b/Help/prop_sf/EXTERNAL_OBJECT.rst
index efa0e9bea..351c04d51 100644
--- a/Help/prop_sf/EXTERNAL_OBJECT.rst
+++ b/Help/prop_sf/EXTERNAL_OBJECT.rst
@@ -3,6 +3,6 @@ EXTERNAL_OBJECT
If set to true then this is an object file.
-If this property is set to true then the source file is really an
+If this property is set to ``True`` then the source file is really an
object file and should not be compiled. It will still be linked into
the target though.
diff --git a/Help/prop_sf/Fortran_FORMAT.rst b/Help/prop_sf/Fortran_FORMAT.rst
index 69e34aafd..1cbbf4809 100644
--- a/Help/prop_sf/Fortran_FORMAT.rst
+++ b/Help/prop_sf/Fortran_FORMAT.rst
@@ -1,9 +1,10 @@
Fortran_FORMAT
--------------
-Set to FIXED or FREE to indicate the Fortran source layout.
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
This property tells CMake whether a given Fortran source file uses
fixed-format or free-format. CMake will pass the corresponding format
-flag to the compiler. Consider using the target-wide Fortran_FORMAT
-property if all source files in a target share the same format.
+flag to the compiler. Consider using the target-wide
+:prop_tgt:`Fortran_FORMAT` property if all source files in a target
+share the same format.
diff --git a/Help/prop_sf/KEEP_EXTENSION.rst b/Help/prop_sf/KEEP_EXTENSION.rst
index d6167e5a9..a32f96834 100644
--- a/Help/prop_sf/KEEP_EXTENSION.rst
+++ b/Help/prop_sf/KEEP_EXTENSION.rst
@@ -6,4 +6,4 @@ Make the output file have the same extension as the source file.
If this property is set then the file extension of the output file
will be the same as that of the source file. Normally the output file
extension is computed based on the language of the source file, for
-example .cxx will go to a .o extension.
+example ``.cxx`` will go to a ``.o`` extension.
diff --git a/Help/prop_sf/LABELS.rst b/Help/prop_sf/LABELS.rst
index e1c10696a..d0d2a0a92 100644
--- a/Help/prop_sf/LABELS.rst
+++ b/Help/prop_sf/LABELS.rst
@@ -4,5 +4,5 @@ LABELS
Specify a list of text labels associated with a source file.
This property has meaning only when the source file is listed in a
-target whose LABELS property is also set. No other semantics are
+target whose ``LABELS`` property is also set. No other semantics are
currently specified.
diff --git a/Help/prop_sf/LANGUAGE.rst b/Help/prop_sf/LANGUAGE.rst
index 97bfa20f4..88d438e7b 100644
--- a/Help/prop_sf/LANGUAGE.rst
+++ b/Help/prop_sf/LANGUAGE.rst
@@ -5,6 +5,7 @@ What programming language is the file.
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
-the file extension. Typical values are CXX C etc. Setting this
+the file extension. Typical values are ``CXX`` (i.e. C++), ``C``,
+``CSharp``, ``CUDA``, ``Fortran``, 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.
diff --git a/Help/prop_sf/OBJECT_OUTPUTS.rst b/Help/prop_sf/OBJECT_OUTPUTS.rst
index 6a2855374..e7e880b29 100644
--- a/Help/prop_sf/OBJECT_OUTPUTS.rst
+++ b/Help/prop_sf/OBJECT_OUTPUTS.rst
@@ -1,9 +1,9 @@
OBJECT_OUTPUTS
--------------
-Additional outputs for a Makefile rule.
+Additional outputs for a :generator:`Ninja` or :ref:`Makefile Generators` rule.
Additional outputs created by compilation of this source file. If any
of these outputs is missing the object will be recompiled. This is
-supported only on Makefile generators and will be ignored on other
-generators.
+supported only on the :generator:`Ninja` and :ref:`Makefile Generators`
+and will be ignored on other generators.
diff --git a/Help/prop_sf/SYMBOLIC.rst b/Help/prop_sf/SYMBOLIC.rst
index c7d0b2603..8bebe30bb 100644
--- a/Help/prop_sf/SYMBOLIC.rst
+++ b/Help/prop_sf/SYMBOLIC.rst
@@ -3,6 +3,6 @@ SYMBOLIC
Is this just a name for a rule.
-If SYMBOLIC (boolean) is set to true the build system will be informed
+If ``SYMBOLIC`` (boolean) is set to ``True`` the build system will be informed
that the source file is not actually created on disk but instead used
as a symbolic name for a build rule.
diff --git a/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst b/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst
new file mode 100644
index 000000000..faac2df7b
--- /dev/null
+++ b/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst
@@ -0,0 +1,5 @@
+Swift_DEPENDENCIES_FILE
+-----------------------
+
+This property sets the path for the Swift dependency file (swiftdeps) for the
+source. If one is not specified, it will default to ``<OBJECT>.swiftdeps``.
diff --git a/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst b/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst
new file mode 100644
index 000000000..5bf5d59cd
--- /dev/null
+++ b/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst
@@ -0,0 +1,4 @@
+Swift_DIAGNOSTICS_FILE
+----------------------
+
+This property controls where the Swift diagnostics are serialized.
diff --git a/Help/prop_sf/VS_CSHARP_tagname.rst b/Help/prop_sf/VS_CSHARP_tagname.rst
index d42159f6d..91c4a06c1 100644
--- a/Help/prop_sf/VS_CSHARP_tagname.rst
+++ b/Help/prop_sf/VS_CSHARP_tagname.rst
@@ -3,8 +3,9 @@ VS_CSHARP_<tagname>
Visual Studio and CSharp source-file-specific configuration.
-Tell the Visual Studio generator to set the source file tag
-``<tagname>`` to a given value in the generated Visual Studio CSharp
+Tell the :manual:`Visual Studio generators <cmake-generators(7)>`
+to set the source file tag ``<tagname>``
+to a given value in the generated Visual Studio CSharp
project. Ignored on other generators and languages. This property
can be used to define dependencies between source files or set any
other Visual Studio specific parameters.
diff --git a/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
index 9fb3ba3d0..6a38478fe 100644
--- a/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
+++ b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
@@ -2,7 +2,8 @@ VS_DEPLOYMENT_CONTENT
---------------------
Mark a source file as content for deployment with a Windows Phone or
-Windows Store application when built with a Visual Studio generator.
+Windows Store application when built with a
+:manual:`Visual Studio generators <cmake-generators(7)>`.
The value must evaluate to either ``1`` or ``0`` and may use
:manual:`generator expressions <cmake-generator-expressions(7)>`
to make the choice based on the build configuration.
diff --git a/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
index 303db952b..2ce22fced 100644
--- a/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
+++ b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
@@ -2,7 +2,8 @@ VS_DEPLOYMENT_LOCATION
----------------------
Specifies the deployment location for a content source file with a Windows
-Phone or Windows Store application when built with a Visual Studio generator.
+Phone or Windows Store application when built
+with a :manual:`Visual Studio generators <cmake-generators(7)>`.
This property is only applicable when using :prop_sf:`VS_DEPLOYMENT_CONTENT`.
The value represent the path relative to the app package and applies to all
configurations.
diff --git a/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
index 30f471d30..db470ef00 100644
--- a/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
+++ b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
@@ -1,6 +1,6 @@
VS_INCLUDE_IN_VSIX
------------------
-Boolean property to specify if the file should be included within a VSIX
-extension package. This is needed for development of Visual Studio
-extensions.
+Boolean property to specify if the file should be included within a
+VSIX (Visual Studio Integration Extension) extension package.
+This is needed for development of Visual Studio extensions.
diff --git a/Help/prop_sf/VS_SHADER_FLAGS.rst b/Help/prop_sf/VS_SHADER_FLAGS.rst
index 09011231b..0a53afd1c 100644
--- a/Help/prop_sf/VS_SHADER_FLAGS.rst
+++ b/Help/prop_sf/VS_SHADER_FLAGS.rst
@@ -1,4 +1,4 @@
VS_SHADER_FLAGS
---------------
-Set additional VS shader flags of a ``.hlsl`` source file.
+Set additional Visual Studio shader flags of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_SHADER_TYPE.rst b/Help/prop_sf/VS_SHADER_TYPE.rst
index 688025608..f1048379a 100644
--- a/Help/prop_sf/VS_SHADER_TYPE.rst
+++ b/Help/prop_sf/VS_SHADER_TYPE.rst
@@ -1,4 +1,4 @@
VS_SHADER_TYPE
--------------
-Set the VS shader type of a ``.hlsl`` source file.
+Set the Visual Studio shader type of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_XAML_TYPE.rst b/Help/prop_sf/VS_XAML_TYPE.rst
index e92191dcb..1a274ba4e 100644
--- a/Help/prop_sf/VS_XAML_TYPE.rst
+++ b/Help/prop_sf/VS_XAML_TYPE.rst
@@ -1,6 +1,7 @@
VS_XAML_TYPE
------------
-Mark a XAML source file as a different type than the default ``Page``.
-The most common usage would be to set the default App.xaml file as
-ApplicationDefinition.
+Mark a Extensible Application Markup Language (XAML) source file
+as a different type than the default ``Page``.
+The most common usage would be to set the default ``App.xaml`` file as
+``ApplicationDefinition``.
diff --git a/Help/prop_sf/WRAP_EXCLUDE.rst b/Help/prop_sf/WRAP_EXCLUDE.rst
index 2c79f72a2..638ff0398 100644
--- a/Help/prop_sf/WRAP_EXCLUDE.rst
+++ b/Help/prop_sf/WRAP_EXCLUDE.rst
@@ -4,7 +4,8 @@ WRAP_EXCLUDE
Exclude this source file from any code wrapping techniques.
Some packages can wrap source files into alternate languages to
-provide additional functionality. For example, C++ code can be
-wrapped into Java or Python etc using SWIG etc. If WRAP_EXCLUDE is
-set to true (1 etc) that indicates that this source file should not be
-wrapped.
+provide additional functionality.
+
+For example, C++ code can be wrapped into Java or Python, using SWIG.
+If ``WRAP_EXCLUDE`` is set to ``True``, that indicates that this
+source file should not be wrapped.
diff --git a/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
index 1b24701a3..b8cf946ea 100644
--- a/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
+++ b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
@@ -1,7 +1,7 @@
XCODE_EXPLICIT_FILE_TYPE
------------------------
-Set the Xcode ``explicitFileType`` attribute on its reference to a
+Set the :generator:`Xcode` ``explicitFileType`` attribute on its reference to a
source file. CMake computes a default based on file extension but
can be told explicitly with this property.
diff --git a/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
index 39e69665a..4c93f444a 100644
--- a/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
+++ b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
@@ -1,9 +1,9 @@
XCODE_FILE_ATTRIBUTES
---------------------
-Add values to the Xcode ``ATTRIBUTES`` setting on its reference to a
+Add values to the :generator:`Xcode` ``ATTRIBUTES`` setting on its reference to a
source file. Among other things, this can be used to set the role on
-a mig file::
+a ``.mig`` file::
set_source_files_properties(defs.mig
PROPERTIES
diff --git a/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
index 42e37574d..b21891fce 100644
--- a/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
+++ b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
@@ -1,8 +1,8 @@
XCODE_LAST_KNOWN_FILE_TYPE
--------------------------
-Set the Xcode ``lastKnownFileType`` attribute on its reference to a
-source file. CMake computes a default based on file extension but
+Set the :generator:`Xcode` ``lastKnownFileType`` attribute on its reference to
+a source file. CMake computes a default based on file extension but
can be told explicitly with this property.
See also :prop_sf:`XCODE_EXPLICIT_FILE_TYPE`, which is preferred
diff --git a/Help/prop_test/COST.rst b/Help/prop_test/COST.rst
index 3236a0295..9300d7b27 100644
--- a/Help/prop_test/COST.rst
+++ b/Help/prop_test/COST.rst
@@ -1,7 +1,14 @@
COST
----
-Set this to a floating point value. Tests in a test set will be run in descending order of cost.
+This property describes the cost of a test. When parallel testing is
+enabled, tests in the test set will be run in descending order of cost.
+Projects can explicitly define the cost of a test by setting this property
+to a floating point value.
-This property describes the cost of a test. You can explicitly set
-this value; tests with higher COST values will run first.
+When the cost of a test is not defined by the project,
+:manual:`ctest <ctest(1)>` will initially use a default cost of ``0``.
+It computes a weighted average of the cost each time a test is run and
+uses that as an improved estimate of the cost for the next run. The more
+a test is re-run in the same build directory, the more representative the
+cost should become.
diff --git a/Help/prop_test/DISABLED.rst b/Help/prop_test/DISABLED.rst
index c18ae7ffa..1d469e80b 100644
--- a/Help/prop_test/DISABLED.rst
+++ b/Help/prop_test/DISABLED.rst
@@ -1,15 +1,15 @@
DISABLED
--------
-If set to true, the test will be skipped and its status will be 'Not Run'. A
-DISABLED test will not be counted in the total number of tests and its
-completion status will be reported to CDash as 'Disabled'.
+If set to ``True``, the test will be skipped and its status will be 'Not Run'. A
+``DISABLED`` test will not be counted in the total number of tests and its
+completion status will be reported to CDash as ``Disabled``.
-A DISABLED test does not participate in test fixture dependency resolution.
-If a DISABLED test has fixture requirements defined in its
+A ``DISABLED`` test does not participate in test fixture dependency resolution.
+If a ``DISABLED`` test has fixture requirements defined in its
:prop_test:`FIXTURES_REQUIRED` property, it will not cause setup or cleanup
tests for those fixtures to be added to the test set.
-If a test with the :prop_test:`FIXTURES_SETUP` property set is DISABLED, the
-fixture behavior will be as though that setup test was passing and any test
+If a test with the :prop_test:`FIXTURES_SETUP` property set is ``DISABLED``,
+the fixture behavior will be as though that setup test was passing and any test
case requiring that fixture will still run.
diff --git a/Help/prop_test/ENVIRONMENT.rst b/Help/prop_test/ENVIRONMENT.rst
index df9bc9e14..102c7922f 100644
--- a/Help/prop_test/ENVIRONMENT.rst
+++ b/Help/prop_test/ENVIRONMENT.rst
@@ -4,6 +4,6 @@ ENVIRONMENT
Specify environment variables that should be defined for running a test.
If set to a list of environment variables and values of the form
-MYVAR=value those environment variables will be defined while running
+``MYVAR=value`` those environment variables will be defined while running
the test. The environment is restored to its previous state after the
test is done.
diff --git a/Help/prop_test/MEASUREMENT.rst b/Help/prop_test/MEASUREMENT.rst
index bc4936e97..de459ed4e 100644
--- a/Help/prop_test/MEASUREMENT.rst
+++ b/Help/prop_test/MEASUREMENT.rst
@@ -1,8 +1,8 @@
MEASUREMENT
-----------
-Specify a CDASH measurement and value to be reported for a test.
+Specify a ``CDASH`` measurement and value to be reported for a test.
-If set to a name then that name will be reported to CDASH as a named
-measurement with a value of 1. You may also specify a value by
-setting MEASUREMENT to "measurement=value".
+If set to a name then that name will be reported to ``CDASH`` as a named
+measurement with a value of ``1``. You may also specify a value by
+setting ``MEASUREMENT`` to ``measurement=value``.
diff --git a/Help/prop_test/RUN_SERIAL.rst b/Help/prop_test/RUN_SERIAL.rst
index 8f65ae18a..ab4c54233 100644
--- a/Help/prop_test/RUN_SERIAL.rst
+++ b/Help/prop_test/RUN_SERIAL.rst
@@ -3,6 +3,6 @@ RUN_SERIAL
Do not run this test in parallel with any other test.
-Use this option in conjunction with the ctest_test PARALLEL_LEVEL
+Use this option in conjunction with the ctest_test ``PARALLEL_LEVEL``
option to specify that this test should not be run in parallel with
any other tests.
diff --git a/Help/prop_test/SKIP_RETURN_CODE.rst b/Help/prop_test/SKIP_RETURN_CODE.rst
index c61273c56..a05fbf3b3 100644
--- a/Help/prop_test/SKIP_RETURN_CODE.rst
+++ b/Help/prop_test/SKIP_RETURN_CODE.rst
@@ -6,4 +6,4 @@ Return code to mark a test as skipped.
Sometimes only a test itself can determine if all requirements for the
test are met. If such a situation should not be considered a hard failure
a return code of the process can be specified that will mark the test as
-"Not Run" if it is encountered.
+``Not Run`` if it is encountered.
diff --git a/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
new file mode 100644
index 000000000..3b9d965f8
--- /dev/null
+++ b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
@@ -0,0 +1,23 @@
+ADDITIONAL_CLEAN_FILES
+----------------------
+
+A :ref:`;-list <CMake Language Lists>` of files or directories that will be
+removed as a part of the global ``clean`` target. It can be used to specify
+files and directories that are generated as part of building the target or
+that are directly associated with the target in some way (e.g. created as a
+result of running the target).
+
+For custom targets, if such files can be captured as outputs or byproducts
+instead, then that should be preferred over adding them to this property.
+If an additional clean file is used by multiple targets or isn't
+target-specific, then the :prop_dir:`ADDITIONAL_CLEAN_FILES` directory
+property may be the more appropriate property to use.
+
+Relative paths are allowed and are interpreted relative to the
+current binary directory.
+
+Contents of ``ADDITIONAL_CLEAN_FILES`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the :generator:`Ninja` and the Makefile
+generators. It is ignored by other generators.
diff --git a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
index 8db6ede91..909b14c34 100644
--- a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
+++ b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
@@ -5,7 +5,7 @@ Directory where :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC`
generate files for the target.
The directory is created on demand and automatically added to the
-:prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES`.
+:prop_tgt:`ADDITIONAL_CLEAN_FILES` target property.
When unset or empty the directory ``<dir>/<target-name>_autogen`` is used where
``<dir>`` is :variable:`CMAKE_CURRENT_BINARY_DIR` and ``<target-name>``
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
index 3e6d5602d..f6dfabdd3 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -1,97 +1,247 @@
AUTOMOC
-------
-Should the target be processed with automoc (for Qt projects).
+Should the target be processed with auto-moc (for Qt projects).
:prop_tgt:`AUTOMOC` is a boolean specifying whether CMake will handle the Qt
``moc`` preprocessor automatically, i.e. without having to use the
-:module:`QT4_WRAP_CPP() <FindQt4>` or QT5_WRAP_CPP() macro.
+:module:`QT4_WRAP_CPP() <FindQt4>` or ``QT5_WRAP_CPP()`` macro.
Currently Qt4 and Qt5 are supported.
+This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
+variable if it is set when a target is created.
+
When this property is set ``ON``, CMake will scan the header and
-source files at build time and invoke moc accordingly.
+source files at build time and invoke ``moc`` accordingly.
-* If an ``#include`` statement like ``#include "moc_<basename>.cpp"`` is found,
- a macro from :prop_tgt:`AUTOMOC_MACRO_NAMES` is expected to appear in the
- ``<basename>.h(xx)`` header file. ``moc`` is run on the header
- file to generate ``moc_<basename>.cpp`` in the
- ``<AUTOGEN_BUILD_DIR>/include`` directory which is automatically added
- to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
- This allows the compiler to find the included ``moc_<basename>.cpp`` file
- regardless of the location the original source.
- * For :prop_gbl:`multi configuration generators <GENERATOR_IS_MULTI_CONFIG>`,
- the include directory is ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``.
+Header file processing
+^^^^^^^^^^^^^^^^^^^^^^
- * See :prop_tgt:`AUTOGEN_BUILD_DIR`.
+At configuration time, a list of header files that should be scanned by
+:prop_tgt:`AUTOMOC` is computed from the target's sources.
-* If an ``#include`` statement like ``#include "<basename>.moc"`` is found,
- a macro from :prop_tgt:`AUTOMOC_MACRO_NAMES` is expected to appear in the
- source file and ``moc`` is run on the source file itself.
+- All header files in the target's sources are added to the scan list.
+- For all C++ source files ``<source_base>.<source_extension>`` in the
+ target's sources, CMake searches for
-* Header files that are not included by an ``#include "moc_<basename>.cpp"``
- statement are nonetheless scanned for a macro out of
- :prop_tgt:`AUTOMOC_MACRO_NAMES`.
- The resulting ``moc_<basename>.cpp`` files are generated in custom
- directories and automatically included in a generated
- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` file,
- which is compiled as part of the target.
+ - a regular header with the same base name
+ (``<source_base>.<header_extention>``) and
+ - a private header with the same base name and a ``_p`` suffix
+ (``<source_base>_p.<header_extention>``)
- * The custom directories with checksum
- based names help to avoid name collisions for ``moc`` files with the same
- ``<basename>``.
+ and adds these to the scan list.
- * See :prop_tgt:`AUTOGEN_BUILD_DIR`.
+At build time, CMake scans each unknown or modified header file from the
+list and searches for
-* Additionally, header files with the same base name as a source file,
- (like ``<basename>.h``) or ``_p`` appended to the base name (like
- ``<basename>_p.h``), are scanned for a macro out of
- :prop_tgt:`AUTOMOC_MACRO_NAMES`, and if found, ``moc``
- is also executed on those files.
+- a Qt macro from :prop_tgt:`AUTOMOC_MACRO_NAMES`,
+- additional file dependencies from the ``FILE`` argument of a
+ ``Q_PLUGIN_METADATA`` macro and
+- additional file dependencies detected by filters defined in
+ :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
-* ``AUTOMOC`` always checks multiple header alternative extensions,
- such as ``hpp``, ``hxx``, etc. when searching for headers.
+If a Qt macro is found, then the header will be compiled by the ``moc`` to the
+output file ``moc_<base_name>.cpp``. The complete output file path is
+described in the section `Output file location`_.
-* ``AUTOMOC`` looks for the ``Q_PLUGIN_METADATA`` macro and reruns the
- ``moc`` when the file addressed by the ``FILE`` argument of the macro changes.
+The header will be ``moc`` compiled again if a file from the additional file
+dependencies changes.
-This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
-variable if it is set when a target is created.
+Header ``moc`` output files ``moc_<base_name>.cpp`` can be included in source
+files. In the section `Including header moc files in sources`_ there is more
+information on that topic.
+
+
+Source file processing
+^^^^^^^^^^^^^^^^^^^^^^
+
+At build time, CMake scans each unknown or modified C++ source file from the
+target's sources for
+
+- a Qt macro from :prop_tgt:`AUTOMOC_MACRO_NAMES`,
+- includes of header ``moc`` files
+ (see `Including header moc files in sources`_),
+- additional file dependencies from the ``FILE`` argument of a
+ ``Q_PLUGIN_METADATA`` macro and
+- additional file dependencies detected by filters defined in
+ :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
+
+If a Qt macro is found, then the C++ source file
+``<base>.<source_extension>`` is expected to as well contain an include
+statement
+
+.. code-block:: c++
+
+ #include <<base>.moc> // or
+ #include "<base>.moc"
+
+The source file then will be compiled by the ``moc`` to the output file
+``<base>.moc``. A description of the complete output file path is in section
+`Output file location`_.
+
+The source will be ``moc`` compiled again if a file from the additional file
+dependencies changes.
+
+Including header moc files in sources
+"""""""""""""""""""""""""""""""""""""
+
+A source file can include the ``moc`` output file of a header
+``<header_base>.<header_extension>`` by using an include statement of
+the form
+
+.. code-block:: c++
+
+ #include <moc_<header_base>.cpp> // or
+ #include "moc_<header_base>.cpp"
+
+If the ``moc`` output file of a header is included by a source, it will
+be generated in a different location than if it was not included. This is
+described in the section `Output file location`_.
+
+
+Output file location
+^^^^^^^^^^^^^^^^^^^^
+
+Included moc output files
+"""""""""""""""""""""""""
+
+``moc`` output files that are included by a source file will be generated in
+
+- ``<AUTOGEN_BUILD_DIR>/include``
+ for single configuration generators or in
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``
+ for :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<AUTOGEN_BUILD_DIR>`` is the value of the target property
+:prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The include directory is automatically added to the target's
+:prop_tgt:`INCLUDE_DIRECTORIES`.
+
+Not included moc output files
+"""""""""""""""""""""""""""""
+
+``moc`` output files that are not included in a source file will be generated
+in
+
+- ``<AUTOGEN_BUILD_DIR>/<SOURCE_DIR_CHECKSUM>``
+ for single configuration generators or in,
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>/<SOURCE_DIR_CHECKSUM>``
+ for :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<SOURCE_DIR_CHECKSUM>`` is a checksum computed from the relative
+parent directory path of the ``moc`` input file. This scheme allows to have
+``moc`` input files with the same name in different directories.
+
+All not included ``moc`` output files will be included automatically by the
+CMake generated file
+
+- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``,
+
+which is added to the target's sources.
+
+
+Qt version detection
+^^^^^^^^^^^^^^^^^^^^
+
+:prop_tgt:`AUTOMOC` enabled targets need to know the Qt major and minor
+version they're working with. The major version usually is provided by the
+``INTERFACE_QT_MAJOR_VERSION`` property of the ``Qt[45]Core`` library,
+that the target links to. To find the minor version, CMake builds a list of
+available Qt versions from
+
+- ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` variables
+ (usually set by ``find_package(Qt5...)``)
+- ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` directory properties
+- ``QT_VERSION_MAJOR`` and ``QT_VERSION_MINOR`` variables
+ (usually set by ``find_package(Qt4...)``)
+- ``QT_VERSION_MAJOR`` and ``QT_VERSION_MINOR`` directory properties
+
+in the context of the :command:`add_executable` or :command:`add_library` call.
+
+Assumed ``INTERFACE_QT_MAJOR_VERSION`` is a valid number, the first
+entry in the list with a matching major version is taken. If no matching major
+version was found, an error is generated.
+If ``INTERFACE_QT_MAJOR_VERSION`` is not a valid number, the first
+entry in the list is taken.
+
+A ``find_package(Qt[45]...)`` call sets the ``QT/Qt5Core_VERSION_MAJOR/MINOR``
+variables. If the call is in a different context than the
+:command:`add_executable` or :command:`add_library` call, e.g. in a function,
+then the version variables might not be available to the :prop_tgt:`AUTOMOC`
+enabled target.
+In that case the version variables can be forwarded from the
+`find_package(Qt[45]...)` calling context to the :command:`add_executable`
+or :command:`add_library` calling context as directory properties.
+The following Qt5 example demonstrates the procedure.
+
+.. code-block:: cmake
+
+ function (add_qt5_client)
+ find_package(Qt5 REQUIRED QUIET COMPONENTS Core Widgets)
+ ...
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}")
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MAJOR}")
+ ...
+ endfunction ()
+ ...
+ add_qt5_client()
+ add_executable(myTarget main.cpp)
+ target_link_libraries(myTarget Qt5::QtWidgets)
+ set_property(TARGET myTarget PROPERTY AUTOMOC ON)
+
+
+Modifiers
+^^^^^^^^^
+:prop_tgt:`AUTOMOC_EXECUTABLE`:
The ``moc`` executable will be detected automatically, but can be forced to
-a certain binary using the :prop_tgt:`AUTOMOC_EXECUTABLE` property.
+a certain binary using this target property.
-Additional command line options for ``moc`` can be set via the
-:prop_tgt:`AUTOMOC_MOC_OPTIONS` property.
+:prop_tgt:`AUTOMOC_MOC_OPTIONS`:
+Additional command line options for ``moc`` can be set in this target property.
-By enabling the :variable:`CMAKE_AUTOMOC_RELAXED_MODE` variable the
-rules for searching the files which will be processed by ``moc`` can be relaxed.
-See the documentation for this variable for more details.
+:prop_tgt:`AUTOMOC_MACRO_NAMES`:
+This list of Qt macro names can be extended to search for additional macros in
+headers and sources.
-The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the
-automoc targets together in an IDE, e.g. in MSVS.
+:prop_tgt:`AUTOMOC_DEPEND_FILTERS`:
+``moc`` dependency file names can be extracted from headers or sources by
+defining file name filters in this target property.
-The global property :prop_gbl:`AUTOGEN_SOURCE_GROUP` can be used to group
-files generated by :prop_tgt:`AUTOMOC` together in an IDE, e.g. in MSVS.
+:prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`:
+Compiler pre definitions for ``moc`` are written to the ``moc_predefs.h`` file.
+The generation of this file can be enabled or disabled in this target property.
-Additional macro names to search for can be added to
-:prop_tgt:`AUTOMOC_MACRO_NAMES`.
+:prop_sf:`SKIP_AUTOMOC`:
+Sources and headers can be excluded from :prop_tgt:`AUTOMOC` processing by
+setting this source file property.
-Additional ``moc`` dependency file names can be extracted from source code
-by using :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
-Compiler pre definitions for ``moc`` are written to a ``moc_predefs.h`` file
-which is controlled by :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`.
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`:
+This global property can be used to group files generated by
+:prop_tgt:`AUTOMOC` or :prop_tgt:`AUTORCC` together in an IDE, e.g. in MSVS.
-Source C++ files can be excluded from :prop_tgt:`AUTOMOC` processing by
-enabling :prop_sf:`SKIP_AUTOMOC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
-The number of parallel ``moc`` processes to start can be modified by
-setting :prop_tgt:`AUTOGEN_PARALLEL`.
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`:
+A global ``autogen`` target, that depends on all :prop_tgt:`AUTOMOC` or
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project,
+will be generated when this variable is ``ON``.
-A global ``autogen`` target that depends on all :prop_tgt:`AUTOMOC` generated
-``<ORIGIN>_autogen`` targets in the project can be generated by enabling
-:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
+:prop_tgt:`AUTOGEN_PARALLEL`:
+This target property controls the number of ``moc`` or ``uic`` processes to
+start in parallel during builds.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst
index 5db6ed02e..cca3e583f 100644
--- a/Help/prop_tgt/AUTORCC.rst
+++ b/Help/prop_tgt/AUTORCC.rst
@@ -1,7 +1,7 @@
AUTORCC
-------
-Should the target be processed with autorcc (for Qt projects).
+Should the target be processed with auto-rcc (for Qt projects).
:prop_tgt:`AUTORCC` is a boolean specifying whether CMake will handle
the Qt ``rcc`` code generator automatically, i.e. without having to use
@@ -13,34 +13,49 @@ as target sources at build time and invoke ``rcc`` accordingly.
This property is initialized by the value of the :variable:`CMAKE_AUTORCC`
variable if it is set when a target is created.
-By default :prop_tgt:`AUTORCC` is processed inside a
+By default :prop_tgt:`AUTORCC` is processed by a
:command:`custom command <add_custom_command>`.
-If the ``.qrc`` file is :prop_sf:`GENERATED` though, a
+If the ``.qrc`` file is :prop_sf:`GENERATED`, a
:command:`custom target <add_custom_target>` is used instead.
-Additional command line options for rcc can be set via the
-:prop_sf:`AUTORCC_OPTIONS` source file property on the ``.qrc`` file.
+When there are multiple ``.qrc`` files with the same name, CMake will
+generate unspecified unique output file names for ``rcc``. Therefore, if
+``Q_INIT_RESOURCE()`` or ``Q_CLEANUP_RESOURCE()`` need to be used, the
+``.qrc`` file name must be unique.
+
+
+Modifiers
+^^^^^^^^^
+:prop_tgt:`AUTORCC_EXECUTABLE`:
The ``rcc`` executable will be detected automatically, but can be forced to
-a certain binary using the :prop_tgt:`AUTORCC_EXECUTABLE` property.
+a certain binary by setting this target property.
-The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group
-the autorcc targets together in an IDE, e.g. in MSVS.
+:prop_sf:`AUTORCC_OPTIONS`:
+Additional command line options for ``rcc`` can be set via this ``.qrc``
+source file property.
-The global property :prop_gbl:`AUTOGEN_SOURCE_GROUP` can be used to group
-files generated by :prop_tgt:`AUTORCC` together in an IDE, e.g. in MSVS.
+:prop_sf:`SKIP_AUTORCC`:
+``.qrc`` files can be excluded from :prop_tgt:`AUTORCC` processing by
+setting this source file property.
-When there are multiple ``.qrc`` files with the same name, CMake will
-generate unspecified unique names for ``rcc``. Therefore if
-``Q_INIT_RESOURCE()`` or ``Q_CLEANUP_RESOURCE()`` need to be used the
-``.qrc`` file name must be unique.
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
+
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`:
+This global property can be used to group files generated by
+:prop_tgt:`AUTOMOC` or :prop_tgt:`AUTORCC` together in an IDE, e.g. in MSVS.
-Source files can be excluded from :prop_tgt:`AUTORCC` processing by
-enabling :prop_sf:`SKIP_AUTORCC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
+:variable:`CMAKE_GLOBAL_AUTORCC_TARGET`:
A global ``autorcc`` target that depends on all :prop_tgt:`AUTORCC` targets
-in the project can be generated by enabling
-:variable:`CMAKE_GLOBAL_AUTORCC_TARGET`.
+in the project will be generated when this variable is ``ON``.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
index 85226c15f..5cf87552c 100644
--- a/Help/prop_tgt/AUTOUIC.rst
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -1,47 +1,82 @@
AUTOUIC
-------
-Should the target be processed with autouic (for Qt projects).
+Should the target be processed with auto-uic (for Qt projects).
:prop_tgt:`AUTOUIC` is a boolean specifying whether CMake will handle
the Qt ``uic`` code generator automatically, i.e. without having to use
the :module:`QT4_WRAP_UI() <FindQt4>` or ``QT5_WRAP_UI()`` macro. Currently
Qt4 and Qt5 are supported.
-When this property is ``ON``, CMake will scan the source files at build time
-and invoke ``uic`` accordingly. If an ``#include`` statement like
-``#include "ui_foo.h"`` is found in ``source.cpp``, a ``foo.ui`` file is
-searched for first in the vicinity of ``source.cpp`` and afterwards in the
-optional :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target.
-``uic`` is run on the ``foo.ui`` file to generate ``ui_foo.h`` in the directory
-``<AUTOGEN_BUILD_DIR>/include``,
-which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+This property is initialized by the value of the :variable:`CMAKE_AUTOUIC`
+variable if it is set when a target is created.
-* For :prop_gbl:`multi configuration generators <GENERATOR_IS_MULTI_CONFIG>`,
- the include directory is ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``.
+When this property is ``ON``, CMake will scan the header and source files at
+build time and invoke ``uic`` accordingly.
-* See :prop_tgt:`AUTOGEN_BUILD_DIR`.
-This property is initialized by the value of the :variable:`CMAKE_AUTOUIC`
-variable if it is set when a target is created.
+Header and source file processing
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At build time, CMake scans each header and source file from the
+target's sources for include statements of the form
+
+.. code-block:: c++
+
+ #include "ui_<ui_base>.h"
+
+Once such an include statement is found in a file, CMake searches for the
+``uic`` input file ``<ui_base>.ui``
+
+- in the vicinity of the file and
+- in the :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target.
-Additional command line options for ``uic`` can be set via the
-:prop_sf:`AUTOUIC_OPTIONS` source file property on the ``foo.ui`` file.
-The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the
-autouic targets together in an IDE, e.g. in MSVS.
+If the ``<ui_base>.ui`` file was found, ``uic`` is called on it to generate
+``ui_<ui_base>.h`` in the directory
+- ``<AUTOGEN_BUILD_DIR>/include`` for single configuration generators or in
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>`` for
+ :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<AUTOGEN_BUILD_DIR>`` is the value of the target property
+:prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The include directory is automatically added to the target's
+:prop_tgt:`INCLUDE_DIRECTORIES`.
+
+
+Modifiers
+^^^^^^^^^
+
+:prop_tgt:`AUTOUIC_EXECUTABLE`:
The ``uic`` executable will be detected automatically, but can be forced to
-a certain binary using the :prop_tgt:`AUTOUIC_EXECUTABLE` property.
+a certain binary using this target property.
+
+:prop_sf:`AUTOUIC_OPTIONS`: Additional command line options for ``uic`` can
+be set via this source file property on a ``<base_name>.ui`` file.
+
+:prop_sf:`SKIP_AUTOUIC`:
+Source files can be excluded from :prop_tgt:`AUTOUIC` processing by setting
+this source file property.
+
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
-Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
-enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
-The number of parallel ``uic`` processes to start can be modified by
-setting :prop_tgt:`AUTOGEN_PARALLEL`.
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`:
+A global ``autogen`` target, that depends on all :prop_tgt:`AUTOMOC` or
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project,
+will be generated when this variable is ``ON``.
-A global ``autogen`` target that depends on all :prop_tgt:`AUTOUIC` generated
-``<ORIGIN>_autogen`` targets in the project can be generated by enabling
-:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
+:prop_tgt:`AUTOGEN_PARALLEL`:
+This target property controls the number of ``moc`` or ``uic`` processes to
+start in parallel during builds.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
index 52ef013da..f261756f1 100644
--- a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,7 @@ generated by the compiler while building source files.
This is a per-configuration version of
:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY`,
-but multi-configuration generators (VS, Xcode) do NOT append a
+but multi-configuration generators (Visual Studio, Xcode) do NOT append a
per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable
diff --git a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
index a0811bcaa..87c5978bc 100644
--- a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
+++ b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
@@ -6,6 +6,10 @@ This command will be added as a prefix to :command:`add_test`,
:command:`add_custom_command`, and :command:`add_custom_target` commands
for built target system executables.
+If this property contains a :ref:`semicolon-separated list <CMake Language
+Lists>`, then the first value is the command and remaining values are its
+arguments.
+
This property is initialized by the value of the
:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
is created.
diff --git a/Help/prop_tgt/DEBUG_POSTFIX.rst b/Help/prop_tgt/DEBUG_POSTFIX.rst
index 1487656d9..04e312e37 100644
--- a/Help/prop_tgt/DEBUG_POSTFIX.rst
+++ b/Help/prop_tgt/DEBUG_POSTFIX.rst
@@ -1,7 +1,7 @@
DEBUG_POSTFIX
-------------
-See target property <CONFIG>_POSTFIX.
+See target property ``<CONFIG>_POSTFIX``.
-This property is a special case of the more-general <CONFIG>_POSTFIX
-property for the DEBUG configuration.
+This property is a special case of the more-general ``<CONFIG>_POSTFIX``
+property for the ``DEBUG`` configuration.
diff --git a/Help/prop_tgt/DEFINE_SYMBOL.rst b/Help/prop_tgt/DEFINE_SYMBOL.rst
index f47f135ea..eb7f93735 100644
--- a/Help/prop_tgt/DEFINE_SYMBOL.rst
+++ b/Help/prop_tgt/DEFINE_SYMBOL.rst
@@ -3,9 +3,9 @@ DEFINE_SYMBOL
Define a symbol when compiling this target's sources.
-DEFINE_SYMBOL sets the name of the preprocessor symbol defined when
+``DEFINE_SYMBOL`` sets the name of the preprocessor symbol defined when
compiling sources in a shared library. If not set here then it is set
-to target_EXPORTS by default (with some substitutions if the target is
+to ``target_EXPORTS`` by default (with some substitutions if the target is
not a valid C identifier). This is useful for headers to know whether
they are being included from inside their library or outside to
properly setup dllexport/dllimport decorations.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
index a2f7d7df7..c100326b9 100644
--- a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -4,7 +4,7 @@ DOTNET_TARGET_FRAMEWORK_VERSION
Specify the .NET target framework version.
Used to specify the .NET target framework version for C++/CLI. For
-example, "v4.5".
+example: ``v4.5``.
This property is only evaluated for :ref:`Visual Studio Generators`
VS 2010 and above.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
index 3aa296d3b..0eee29792 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
@@ -1,15 +1,12 @@
EXCLUDE_FROM_ALL
----------------
-Set this target property to a true (or false) value to exclude (or include)
-the target from the "all" target of the containing directory and its
-ancestors. If excluded, running e.g. ``make`` in the containing directory
-or its ancestors will not build the target by default.
+Exclude the target from the all target.
-If this target property is not set then the target will be included in
-the "all" target of the containing directory. Furthermore, it will be
-included in the "all" target of its ancestor directories unless the
-:prop_dir:`EXCLUDE_FROM_ALL` directory property is set.
+A property on a target that indicates if the target is excluded from
+the default build target. If it is not, then with a Makefile for
+example typing make will cause this target to be built. The same
+concept applies to the default build of other generators.
With ``EXCLUDE_FROM_ALL`` set to false or not set at all, the target
will be brought up to date as part of doing a ``make install`` or its
@@ -19,3 +16,6 @@ target has undefined behavior. Note that such a target can still safely
be listed in an :command:`install(TARGETS)` command as long as the install
components the target belongs to are not part of the set of components
that anything tries to install.
+
+This property is enabled by default for targets that are created in
+directories that have :prop_dir:`EXCLUDE_FROM_ALL` set to ``TRUE``.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
index a14e48c19..664704bfa 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
@@ -1,8 +1,8 @@
EXCLUDE_FROM_DEFAULT_BUILD
--------------------------
-Exclude target from "Build Solution".
+Exclude target from ``Build Solution``.
This property is only used by Visual Studio generators.
-When set to TRUE, the target will not be built when you press "Build
-Solution".
+When set to ``TRUE``, the target will not be built when you press
+``Build Solution``.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
index 655a9dee0..ad1021aa4 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
@@ -1,9 +1,10 @@
EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>
-----------------------------------
-Per-configuration version of target exclusion from "Build Solution".
+Per-configuration version of target exclusion from ``Build Solution``.
This is the configuration-specific version of
-EXCLUDE_FROM_DEFAULT_BUILD. If the generic EXCLUDE_FROM_DEFAULT_BUILD
-is also set on a target, EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG> takes
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD`. If the generic
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD` is also set on a target,
+``EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>`` takes
precedence in configurations for which it has a value.
diff --git a/Help/prop_tgt/EXPORT_NAME.rst b/Help/prop_tgt/EXPORT_NAME.rst
index 1b4247cc5..0e021d0db 100644
--- a/Help/prop_tgt/EXPORT_NAME.rst
+++ b/Help/prop_tgt/EXPORT_NAME.rst
@@ -3,6 +3,6 @@ EXPORT_NAME
Exported name for target files.
-This sets the name for the IMPORTED target generated when it this
-target is is exported. If not set, the logical target name is used by
-default.
+This sets the name for the ``IMPORTED`` target generated by the
+:command:`install(EXPORT)` and :command:`export` commands.
+If not set, the logical target name is used by default.
diff --git a/Help/prop_tgt/EchoString.rst b/Help/prop_tgt/EchoString.rst
index 32ae2aa8f..352d06258 100644
--- a/Help/prop_tgt/EchoString.rst
+++ b/Help/prop_tgt/EchoString.rst
@@ -3,5 +3,5 @@ EchoString
A message to be displayed when the target is built.
-A message to display on some generators (such as makefiles) when the
-target is built.
+A message to display on some generators (such as :ref:`Makefile Generators`)
+when the target is built.
diff --git a/Help/prop_tgt/FOLDER.rst b/Help/prop_tgt/FOLDER.rst
index 0121125e4..f6be9e673 100644
--- a/Help/prop_tgt/FOLDER.rst
+++ b/Help/prop_tgt/FOLDER.rst
@@ -3,10 +3,10 @@ FOLDER
Set the folder name. Use to organize targets in an IDE.
-Targets with no FOLDER property will appear as top level entities in
-IDEs like Visual Studio. Targets with the same FOLDER property value
+Targets with no ``FOLDER`` property will appear as top level entities in
+IDEs like Visual Studio. Targets with the same ``FOLDER`` property value
will appear next to each other in a folder of that name. To nest
-folders, use FOLDER values such as 'GUI/Dialogs' with '/' characters
+folders, use ``FOLDER`` values such as 'GUI/Dialogs' with '/' characters
separating folder levels.
This property is initialized by the value of the variable
diff --git a/Help/prop_tgt/FRAMEWORK.rst b/Help/prop_tgt/FRAMEWORK.rst
index 9dad06052..3dff1be3c 100644
--- a/Help/prop_tgt/FRAMEWORK.rst
+++ b/Help/prop_tgt/FRAMEWORK.rst
@@ -6,7 +6,9 @@ Build ``SHARED`` or ``STATIC`` library as Framework Bundle on the macOS and iOS.
If such a library target has this property set to ``TRUE`` it will be
built as a framework when built on the macOS and iOS. It will have the
directory structure required for a framework and will be suitable to
-be used with the ``-framework`` option
+be used with the ``-framework`` option. This property is initialized by the
+value of the :variable:`CMAKE_FRAMEWORK` variable if it is set when a target is
+created.
To customize ``Info.plist`` file in the framework, use
:prop_tgt:`MACOSX_FRAMEWORK_INFO_PLIST` target property.
diff --git a/Help/prop_tgt/Fortran_FORMAT.rst b/Help/prop_tgt/Fortran_FORMAT.rst
index 0a11d91ca..8704e5f42 100644
--- a/Help/prop_tgt/Fortran_FORMAT.rst
+++ b/Help/prop_tgt/Fortran_FORMAT.rst
@@ -1,11 +1,11 @@
Fortran_FORMAT
--------------
-Set to FIXED or FREE to indicate the Fortran source layout.
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
This property tells CMake whether the Fortran source files in a target
use fixed-format or free-format. CMake will pass the corresponding
-format flag to the compiler. Use the source-specific Fortran_FORMAT
+format flag to the compiler. Use the source-specific ``Fortran_FORMAT``
property to change the format of a specific source file. If the
-variable CMAKE_Fortran_FORMAT is set when a target is created its
+variable :variable:`CMAKE_Fortran_FORMAT` is set when a target is created its
value is used to initialize this property.
diff --git a/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
index 9c8643764..e061863b3 100644
--- a/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
+++ b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
@@ -8,10 +8,10 @@ the compiler supports a module output directory this specifies the
directory in which the modules will be placed. When this property is
not set the modules will be placed in the build directory
corresponding to the target's source directory. If the variable
-CMAKE_Fortran_MODULE_DIRECTORY is set when a target is created its
+:variable:`CMAKE_Fortran_MODULE_DIRECTORY` is set when a target is created its
value is used to initialize this property.
Note that some compilers will automatically search the module output
directory for modules USEd during compilation but others will not. If
your sources USE modules their location must be specified by
-INCLUDE_DIRECTORIES regardless of this property.
+:prop_tgt:`INCLUDE_DIRECTORIES` regardless of this property.
diff --git a/Help/prop_tgt/GENERATOR_FILE_NAME.rst b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
index 032b22acf..a48610550 100644
--- a/Help/prop_tgt/GENERATOR_FILE_NAME.rst
+++ b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
@@ -6,4 +6,4 @@ Generator's file for this target.
An internal property used by some generators to record the name of the
project or dsp file associated with this target. Note that at
configure time, this property is only set for targets created by
-include_external_msproject().
+:command:`include_external_msproject`.
diff --git a/Help/prop_tgt/GHS_INTEGRITY_APP.rst b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
index 764303850..b6697817a 100644
--- a/Help/prop_tgt/GHS_INTEGRITY_APP.rst
+++ b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
@@ -4,7 +4,7 @@ GHS_INTEGRITY_APP
``ON`` / ``OFF`` boolean to determine if an executable target should
be treated as an `Integrity Application`.
-If no value is set and if a `.int` file is added as a source file to the
+If no value is set and if a ``.int`` file is added as a source file to the
executable target it will be treated as an `Integrity Application`.
Supported on :generator:`Green Hills MULTI`.
diff --git a/Help/prop_tgt/GNUtoMS.rst b/Help/prop_tgt/GNUtoMS.rst
index cf34da9c3..a09ebbfae 100644
--- a/Help/prop_tgt/GNUtoMS.rst
+++ b/Help/prop_tgt/GNUtoMS.rst
@@ -1,17 +1,17 @@
GNUtoMS
-------
-Convert GNU import library (.dll.a) to MS format (.lib).
+Convert GNU import library (``.dll.a``) to MS format (``.lib``).
When linking a shared library or executable that exports symbols using
GNU tools on Windows (MinGW/MSYS) with Visual Studio installed convert
-the import library (.dll.a) from GNU to MS format (.lib). Both import
-libraries will be installed by install(TARGETS) and exported by
-install(EXPORT) and export() to be linked by applications with either
-GNU- or MS-compatible tools.
+the import library (``.dll.a``) from GNU to MS format (``.lib``). Both import
+libraries will be installed by :command:`install(TARGETS)` and exported by
+:command:`install(EXPORT)` and :command:`export` to be linked
+by applications with either GNU- or MS-compatible tools.
-If the variable CMAKE_GNUtoMS is set when a target is created its
+If the variable ``CMAKE_GNUtoMS`` is set when a target is created its
value is used to initialize this property. The variable must be set
-prior to the first command that enables a language such as project()
-or enable_language(). CMake provides the variable as an option to the
+prior to the first command that enables a language such as :command:`project`
+or :command:`enable_language`. CMake provides the variable as an option to the
user automatically when configuring on Windows with GNU tools.
diff --git a/Help/prop_tgt/HAS_CXX.rst b/Help/prop_tgt/HAS_CXX.rst
index 7790932ae..15199b15b 100644
--- a/Help/prop_tgt/HAS_CXX.rst
+++ b/Help/prop_tgt/HAS_CXX.rst
@@ -3,5 +3,5 @@ HAS_CXX
Link the target using the C++ linker tool (obsolete).
-This is equivalent to setting the LINKER_LANGUAGE property to CXX.
-See that property's documentation for details.
+This is equivalent to setting the :prop_tgt:`LINKER_LANGUAGE`
+property to ``CXX``.
diff --git a/Help/prop_tgt/IMPORTED.rst b/Help/prop_tgt/IMPORTED.rst
index 605c1ce6c..22d28aaf7 100644
--- a/Help/prop_tgt/IMPORTED.rst
+++ b/Help/prop_tgt/IMPORTED.rst
@@ -1,8 +1,8 @@
IMPORTED
--------
-Read-only indication of whether a target is IMPORTED.
+Read-only indication of whether a target is ``IMPORTED``.
The boolean value of this property is ``True`` for targets created with
-the IMPORTED option to :command:`add_executable` or :command:`add_library`.
+the ``IMPORTED`` option to :command:`add_executable` or :command:`add_library`.
It is ``False`` for targets built within the project.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB.rst b/Help/prop_tgt/IMPORTED_IMPLIB.rst
index acf4b321f..77fb552ea 100644
--- a/Help/prop_tgt/IMPORTED_IMPLIB.rst
+++ b/Help/prop_tgt/IMPORTED_IMPLIB.rst
@@ -1,7 +1,7 @@
IMPORTED_IMPLIB
---------------
-Full path to the import library for an IMPORTED target.
+Full path to the import library for an ``IMPORTED`` target.
-Set this to the location of the ".lib" part of a windows DLL. Ignored
+Set this to the location of the ``.lib`` part of a Windows DLL. Ignored
for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
index b4b3f0228..5debabc95 100644
--- a/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_IMPLIB_<CONFIG>
------------------------
-<CONFIG>-specific version of IMPORTED_IMPLIB property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_IMPLIB` property.
Configuration names correspond to those provided by the project from
which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
index 2db2b0e58..f7e216581 100644
--- a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
@@ -8,7 +8,7 @@ their implementation. On some platforms the linker searches for the
dependent libraries of shared libraries they are including in the
link. Set this property to the list of dependent shared libraries of
an imported library. The list should be disjoint from the list of
-interface libraries in the INTERFACE_LINK_LIBRARIES property. On
+interface libraries in the :prop_tgt:`INTERFACE_LINK_LIBRARIES` property. On
platforms requiring dependent shared libraries to be found at link
time CMake uses this list to add appropriate files or paths to the
link command line. Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
index ee243c75d..5b9c51308 100644
--- a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>
------------------------------------------
-<CONFIG>-specific version of IMPORTED_LINK_DEPENDENT_LIBRARIES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_DEPENDENT_LIBRARIES`.
Configuration names correspond to those provided by the project from
which the target is imported. If set, this property completely
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
index 5ca9c8b6f..4ed4281f3 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
@@ -1,14 +1,14 @@
IMPORTED_LINK_INTERFACE_LANGUAGES
---------------------------------
-Languages compiled into an IMPORTED static library.
+Languages compiled into an ``IMPORTED`` static library.
Set this to the list of languages of source files compiled to produce
-a STATIC IMPORTED library (such as "C" or "CXX"). CMake accounts for
+a ``STATIC IMPORTED`` library (such as ``C`` or ``CXX``). CMake accounts for
these languages when computing how to link a target to the imported
library. For example, when a C executable links to an imported C++
static library CMake chooses the C++ linker to satisfy language
runtime dependencies of the static library.
-This property is ignored for targets that are not STATIC libraries.
+This property is ignored for targets that are not ``STATIC`` libraries.
This property is ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
index d4a10fbdd..40fcf7fcf 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_LINK_INTERFACE_LANGUAGES_<CONFIG>
------------------------------------------
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_LANGUAGES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LANGUAGES`.
Configuration names correspond to those provided by the project from
which the target is imported. If set, this property completely
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
index 61134a401..527cf2ebe 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
@@ -1,16 +1,16 @@
IMPORTED_LINK_INTERFACE_LIBRARIES
---------------------------------
-Transitive link interface of an IMPORTED target.
+Transitive link interface of an ``IMPORTED`` target.
Set this to the list of libraries whose interface is included when an
-IMPORTED library target is linked to another target. The libraries
+``IMPORTED`` library target is linked to another target. The libraries
will be included on the link line for the target. Unlike the
-LINK_INTERFACE_LIBRARIES property, this property applies to all
-imported target types, including STATIC libraries. This property is
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` property, this property applies to all
+imported target types, including ``STATIC`` libraries. This property is
ignored for non-imported targets.
This property is ignored if the target also has a non-empty
-INTERFACE_LINK_LIBRARIES property.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
-This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead.
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
index 13b93ba98..050fb1dff 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
@@ -1,13 +1,13 @@
IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>
------------------------------------------
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_LIBRARIES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LIBRARIES`.
Configuration names correspond to those provided by the project from
which the target is imported. If set, this property completely
overrides the generic property for the named configuration.
This property is ignored if the target also has a non-empty
-INTERFACE_LINK_LIBRARIES property.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
-This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead.
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
index 3a86b9985..7a92d96b6 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
@@ -1,6 +1,6 @@
IMPORTED_LINK_INTERFACE_MULTIPLICITY
------------------------------------
-Repetition count for cycles of IMPORTED static libraries.
+Repetition count for cycles of ``IMPORTED`` static libraries.
-This is LINK_INTERFACE_MULTIPLICITY for IMPORTED targets.
+This is :prop_tgt:`LINK_INTERFACE_MULTIPLICITY` for ``IMPORTED`` targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
index 33b9b8419..758237bf1 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_LINK_INTERFACE_MULTIPLICITY_<CONFIG>
---------------------------------------------
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_MULTIPLICITY.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_MULTIPLICITY`.
If set, this property completely overrides the generic property for
the named configuration.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION.rst b/Help/prop_tgt/IMPORTED_LOCATION.rst
index 2d07aadcf..a9123cdd9 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION.rst
@@ -1,21 +1,28 @@
IMPORTED_LOCATION
-----------------
-Full path to the main file on disk for an IMPORTED target.
+Full path to the main file on disk for an ``IMPORTED`` target.
-Set this to the location of an IMPORTED target file on disk. For
+Set this to the location of an ``IMPORTED`` target file on disk. For
executables this is the location of the executable file. For bundles
on macOS this is the location of the executable file inside
-Contents/MacOS under the application bundle folder. For static
+``Contents/MacOS`` under the application bundle folder. For ``STATIC``
libraries and modules this is the location of the library or module.
-For shared libraries on non-DLL platforms this is the location of the
+For ``SHARED`` libraries on non-DLL platforms this is the location of the
shared library. For frameworks on macOS this is the location of the
library file symlink just inside the framework folder. For DLLs this
-is the location of the ".dll" part of the library. For UNKNOWN
+is the location of the ``.dll`` part of the library. For ``UNKNOWN``
libraries this is the location of the file to be linked. Ignored for
non-imported targets.
-Projects may skip IMPORTED_LOCATION if the configuration-specific
-property IMPORTED_LOCATION_<CONFIG> is set. To get the location of an
-imported target read one of the LOCATION or LOCATION_<CONFIG>
-properties.
+The ``IMPORTED_LOCATION`` target property may be overridden for a
+given configuration ``<CONFIG>`` by the configuration-specific
+:prop_tgt:`IMPORTED_LOCATION_<CONFIG>` target property. Furthermore,
+the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` target property may be
+used to map between a project's configurations and those of an imported
+target. If none of these is set then the name of any other configuration
+listed in the :prop_tgt:`IMPORTED_CONFIGURATIONS` target property may be
+selected and its :prop_tgt:`IMPORTED_LOCATION_<CONFIG>` value used.
+
+To get the location of an imported target read one of the :prop_tgt:`LOCATION`
+or ``LOCATION_<CONFIG>`` properties.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
index f85bb19c9..c5f5f048c 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_LOCATION_<CONFIG>
--------------------------
-<CONFIG>-specific version of IMPORTED_LOCATION property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LOCATION` property.
Configuration names correspond to those provided by the project from
which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME.rst b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
index 4a1bb447a..cbb764226 100644
--- a/Help/prop_tgt/IMPORTED_NO_SONAME.rst
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
@@ -1,9 +1,9 @@
IMPORTED_NO_SONAME
------------------
-Specifies that an IMPORTED shared library target has no "soname".
+Specifies that an ``IMPORTED`` shared library target has no ``soname``.
Set this property to true for an imported shared library file that has
-no "soname" field. CMake may adjust generated link commands for some
+no ``soname`` field. CMake may adjust generated link commands for some
platforms to prevent the linker from using the path to the library in
-place of its missing soname. Ignored for non-imported targets.
+place of its missing ``soname``. Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
index 22d68220c..76fe471f4 100644
--- a/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_NO_SONAME_<CONFIG>
---------------------------
-<CONFIG>-specific version of IMPORTED_NO_SONAME property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_NO_SONAME` property.
Configuration names correspond to those provided by the project from
which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_SONAME.rst b/Help/prop_tgt/IMPORTED_SONAME.rst
index d80907e3e..bf0c3cbc1 100644
--- a/Help/prop_tgt/IMPORTED_SONAME.rst
+++ b/Help/prop_tgt/IMPORTED_SONAME.rst
@@ -1,8 +1,8 @@
IMPORTED_SONAME
---------------
-The "soname" of an IMPORTED target of shared library type.
+The ``soname`` of an ``IMPORTED`` target of shared library type.
-Set this to the "soname" embedded in an imported shared library. This
+Set this to the ``soname`` embedded in an imported shared library. This
is meaningful only on platforms supporting the feature. Ignored for
non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
index 6ec9af3f8..59a9d1a45 100644
--- a/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
@@ -1,7 +1,7 @@
IMPORTED_SONAME_<CONFIG>
------------------------
-<CONFIG>-specific version of IMPORTED_SONAME property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_SONAME` property.
Configuration names correspond to those provided by the project from
which the target is imported.
diff --git a/Help/prop_tgt/IMPORT_PREFIX.rst b/Help/prop_tgt/IMPORT_PREFIX.rst
index deede9788..17e381be4 100644
--- a/Help/prop_tgt/IMPORT_PREFIX.rst
+++ b/Help/prop_tgt/IMPORT_PREFIX.rst
@@ -3,7 +3,7 @@ IMPORT_PREFIX
What comes before the import library name.
-Similar to the target property PREFIX, but used for import libraries
-(typically corresponding to a DLL) instead of regular libraries. A
-target property that can be set to override the prefix (such as "lib")
+Similar to the target property :prop_tgt:`PREFIX`, but used for import libraries
+(typically corresponding to a ``DLL``) instead of regular libraries. A
+target property that can be set to override the prefix (such as ``lib``)
on an import library name.
diff --git a/Help/prop_tgt/IMPORT_SUFFIX.rst b/Help/prop_tgt/IMPORT_SUFFIX.rst
index bd0125037..9307115b4 100644
--- a/Help/prop_tgt/IMPORT_SUFFIX.rst
+++ b/Help/prop_tgt/IMPORT_SUFFIX.rst
@@ -3,7 +3,7 @@ IMPORT_SUFFIX
What comes after the import library name.
-Similar to the target property SUFFIX, but used for import libraries
-(typically corresponding to a DLL) instead of regular libraries. A
-target property that can be set to override the suffix (such as
-".lib") on an import library name.
+Similar to the target property :prop_tgt:`SUFFIX`, but used
+for import libraries (typically corresponding to a ``DLL``) instead of
+regular libraries. A target property that can be set to override
+the suffix (such as ``.lib``) on an import library name.
diff --git a/Help/prop_tgt/INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
index 8b40d9c34..b381d1dbd 100644
--- a/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
+++ b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
@@ -18,7 +18,7 @@ paths for the compiler.
Relative paths should not be added to this property directly. Use one of
the commands above instead to handle relative paths.
-Contents of ``INCLUDE_DIRECTORIES`` may use "generator expressions" with
+Contents of ``INCLUDE_DIRECTORIES`` may use :manual:`cmake-generator-expressions(7)` 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.
diff --git a/Help/prop_tgt/INSTALL_NAME_DIR.rst b/Help/prop_tgt/INSTALL_NAME_DIR.rst
index 34348bb9b..2216072ac 100644
--- a/Help/prop_tgt/INSTALL_NAME_DIR.rst
+++ b/Help/prop_tgt/INSTALL_NAME_DIR.rst
@@ -1,10 +1,10 @@
INSTALL_NAME_DIR
----------------
-Mac OSX directory name for installed targets.
+macOS directory name for installed targets.
-INSTALL_NAME_DIR is a string specifying the directory portion of the
-"install_name" field of shared libraries on Mac OSX to use in the
+``INSTALL_NAME_DIR`` is a string specifying the directory portion of the
+"install_name" field of shared libraries on macOS to use in the
installed targets.
This property is initialized by the value of the variable
diff --git a/Help/prop_tgt/INSTALL_RPATH.rst b/Help/prop_tgt/INSTALL_RPATH.rst
index 6206b6889..6403f4c67 100644
--- a/Help/prop_tgt/INSTALL_RPATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH.rst
@@ -5,5 +5,5 @@ The rpath to use for installed targets.
A semicolon-separated list specifying the rpath to use in installed
targets (for platforms that support it). This property is initialized
-by the value of the variable CMAKE_INSTALL_RPATH if it is set when a
-target is created.
+by the value of the variable :variable:`CMAKE_INSTALL_RPATH` if it is set when
+a target is created.
diff --git a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
index f0006f85b..d8be9548a 100644
--- a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,8 +3,8 @@ INSTALL_RPATH_USE_LINK_PATH
Add paths to linker search and installed rpath.
-INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true will
+``INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True`` will
append directories in the linker search path and outside the project
-to the INSTALL_RPATH. This property is initialized by the value of
-the variable CMAKE_INSTALL_RPATH_USE_LINK_PATH if it is set when a
+to the :prop_tgt:`INSTALL_RPATH`. This property is initialized by the value of
+the variable ``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` if it is set when a
target is created.
diff --git a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
index d07f8ea03..790554d9f 100644
--- a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
@@ -3,9 +3,10 @@ INTERFACE_LINK_DEPENDS
Additional public interface files on which a target binary depends for linking.
-This property is supported only by Makefile and Ninja generators. It is
-intended to specify dependencies on "linker scripts" for custom Makefile link
-rules.
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`.
+It is intended to specify dependencies on "linker scripts" for
+custom Makefile link rules.
When target dependencies are specified using :command:`target_link_libraries`,
CMake will read this property from all target dependencies to determine the
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
index 3f68c3128..d3a5e9414 100644
--- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
@@ -4,7 +4,9 @@ INTERPROCEDURAL_OPTIMIZATION
Enable interprocedural optimization for a target.
If set to true, enables interprocedural optimizations if they are
-known to be supported by the compiler.
+known :module:`to be supported <CheckIPOSupported>` by the compiler. Depending
+on value of policy :policy:`CMP0069`, the error will be reported or ignored,
+if interprocedural optimization is enabled but not supported.
This property is initialized by the
:variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION` variable if it is set when a
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 782b0f0a6..79d46048b 100644
--- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -3,7 +3,7 @@ INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
Per-configuration interprocedural optimization for a target.
-This is a per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
+This is a per-configuration version of :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`.
If set, this property overrides the generic property for the named
configuration.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
index 28dd404df..5cefc38bb 100644
--- a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,8 @@ Per-configuration output directory for
This is a per-configuration version of the
:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY` target property, but
-multi-configuration generators (VS, Xcode) do NOT append a
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if
diff --git a/Help/prop_tgt/LINKER_LANGUAGE.rst b/Help/prop_tgt/LINKER_LANGUAGE.rst
index b1ca86710..b0a572b5c 100644
--- a/Help/prop_tgt/LINKER_LANGUAGE.rst
+++ b/Help/prop_tgt/LINKER_LANGUAGE.rst
@@ -8,7 +8,7 @@ whose compiler is used to link the target (such as "C" or "CXX"). A
typical value for an executable is the language of the source file
providing the program entry point (main). If not set, the language
with the highest linker preference value is the default. See
-documentation of CMAKE_<LANG>_LINKER_PREFERENCE variables.
+documentation of :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` variables.
If this property is not set by the user, it will be calculated at
generate-time by CMake.
diff --git a/Help/prop_tgt/LINK_DEPENDS.rst b/Help/prop_tgt/LINK_DEPENDS.rst
index 3ab8658e8..e59d4c014 100644
--- a/Help/prop_tgt/LINK_DEPENDS.rst
+++ b/Help/prop_tgt/LINK_DEPENDS.rst
@@ -7,7 +7,8 @@ Specifies a semicolon-separated list of full-paths to files on which
the link rule for this target depends. The target binary will be
linked if any of the named files is newer than it.
-This property is supported only by Makefile and Ninja generators. It is
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`. It is
intended to specify dependencies on "linker scripts" for custom Makefile link
rules.
diff --git a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
index e3918ca44..68c312932 100644
--- a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
+++ b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
@@ -1,8 +1,8 @@
LINK_FLAGS_<CONFIG>
-------------------
-Per-configuration linker flags for a shared library, module or executable
-target.
+Per-configuration linker flags for a ``SHARED`` library, ``MODULE`` or
+``EXECUTABLE`` target.
This is the configuration-specific version of :prop_tgt:`LINK_FLAGS`.
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
index 4e26388a9..b798af954 100644
--- a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
@@ -1,9 +1,9 @@
LINK_INTERFACE_MULTIPLICITY
---------------------------
-Repetition count for STATIC libraries with cyclic dependencies.
+Repetition count for ``STATIC`` libraries with cyclic dependencies.
-When linking to a STATIC library target with cyclic dependencies the
+When linking to a ``STATIC`` library target with cyclic dependencies the
linker may need to scan more than once through the archives in the
strongly connected component of the dependency graph. CMake by
default constructs the link line so that the linker will scan through
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
index 5ea4a45cf..7c9461fde 100644
--- a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -1,8 +1,8 @@
LINK_INTERFACE_MULTIPLICITY_<CONFIG>
------------------------------------
-Per-configuration repetition count for cycles of STATIC libraries.
+Per-configuration repetition count for cycles of ``STATIC`` libraries.
This is the configuration-specific version of
-LINK_INTERFACE_MULTIPLICITY. If set, this property completely
+:prop_tgt:`LINK_INTERFACE_MULTIPLICITY`. If set, this property completely
overrides the generic property for the named configuration.
diff --git a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
index cf9c87147..fecbb1480 100644
--- a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
@@ -3,16 +3,17 @@ LINK_SEARCH_END_STATIC
End a link line such that static system libraries are used.
-Some linkers support switches such as -Bstatic and -Bdynamic to
-determine whether to use static or shared libraries for -lXXX options.
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
CMake uses these options to set the link type for libraries whose full
paths are not known or (in some cases) are in implicit link
directories for the platform. By default CMake adds an option at the
end of the library list (if necessary) to set the linker search type
back to its starting type. This property switches the final linker
-search type to -Bstatic regardless of how it started.
+search type to ``-Bstatic`` regardless of how it started.
This property is initialized by the value of the variable
-CMAKE_LINK_SEARCH_END_STATIC if it is set when a target is created.
+:variable:`CMAKE_LINK_SEARCH_END_STATIC` if it is set
+when a target is created.
-See also LINK_SEARCH_START_STATIC.
+See also :prop_tgt:`LINK_SEARCH_START_STATIC`.
diff --git a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
index 2e0f9bd33..83cf231c5 100644
--- a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
@@ -3,17 +3,18 @@ LINK_SEARCH_START_STATIC
Assume the linker looks for static libraries by default.
-Some linkers support switches such as -Bstatic and -Bdynamic to
-determine whether to use static or shared libraries for -lXXX options.
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
CMake uses these options to set the link type for libraries whose full
paths are not known or (in some cases) are in implicit link
directories for the platform. By default the linker search type is
-assumed to be -Bdynamic at the beginning of the library list. This
-property switches the assumption to -Bstatic. It is intended for use
-when linking an executable statically (e.g. with the GNU -static
+assumed to be ``-Bdynamic`` at the beginning of the library list. This
+property switches the assumption to ``-Bstatic``. It is intended for use
+when linking an executable statically (e.g. with the GNU ``-static``
option).
This property is initialized by the value of the variable
-CMAKE_LINK_SEARCH_START_STATIC if it is set when a target is created.
+ :variable:`CMAKE_LINK_SEARCH_START_STATIC` if it is set
+ when a target is created.
-See also LINK_SEARCH_END_STATIC.
+See also :prop_tgt:`LINK_SEARCH_END_STATIC`.
diff --git a/Help/prop_tgt/LOCATION.rst b/Help/prop_tgt/LOCATION.rst
index 16d5696e5..d058064d6 100644
--- a/Help/prop_tgt/LOCATION.rst
+++ b/Help/prop_tgt/LOCATION.rst
@@ -4,24 +4,25 @@ LOCATION
Read-only location of a target on disk.
For an imported target, this read-only property returns the value of
-the LOCATION_<CONFIG> property for an unspecified configuration
-<CONFIG> provided by the target.
+the ``LOCATION_<CONFIG>`` property for an unspecified configuration
+``<CONFIG>`` provided by the target.
For a non-imported target, this property is provided for compatibility
with CMake 2.4 and below. It was meant to get the location of an
-executable target's output file for use in add_custom_command. The
+executable target's output file for use in :command:`add_custom_command`. The
path may contain a build-system-specific portion that is replaced at
build time with the configuration getting built (such as
-"$(ConfigurationName)" in VS). In CMake 2.6 and above
-add_custom_command automatically recognizes a target name in its
-COMMAND and DEPENDS options and computes the target location. In
-CMake 2.8.4 and above add_custom_command recognizes generator
-expressions to refer to target locations anywhere in the command.
+``$(ConfigurationName)`` in VS). In CMake 2.6 and above
+:command:`add_custom_command` automatically recognizes a target name in its
+``COMMAND`` and ``DEPENDS`` options and computes the target location. In
+CMake 2.8.4 and above :command:`add_custom_command` recognizes
+:manual:`generator expressions <cmake-generator-expressions(7)>`
+to refer to target locations anywhere in the command.
Therefore this property is not needed for creating custom commands.
Do not set properties that affect the location of a target after
reading this property. These include properties whose names match
-"(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?",
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
``(IMPLIB_)?(PREFIX|SUFFIX)``, or "LINKER_LANGUAGE". Failure to follow
this rule is not diagnosed and leaves the location of the target
undefined.
diff --git a/Help/prop_tgt/LOCATION_CONFIG.rst b/Help/prop_tgt/LOCATION_CONFIG.rst
index ac6bdb786..67de8ed21 100644
--- a/Help/prop_tgt/LOCATION_CONFIG.rst
+++ b/Help/prop_tgt/LOCATION_CONFIG.rst
@@ -4,17 +4,17 @@ LOCATION_<CONFIG>
Read-only property providing a target location on disk.
A read-only property that indicates where a target's main file is
-located on disk for the configuration <CONFIG>. The property is
+located on disk for the configuration ``<CONFIG>``. The property is
defined only for library and executable targets. An imported target
may provide a set of configurations different from that of the
importing project. By default CMake looks for an exact-match but
otherwise uses an arbitrary available configuration. Use the
-MAP_IMPORTED_CONFIG_<CONFIG> property to map imported configurations
-explicitly.
+:prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` property to map imported
+configurations explicitly.
Do not set properties that affect the location of a target after
reading this property. These include properties whose names match
-"(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?",
-``(IMPLIB_)?(PREFIX|SUFFIX)``, or "LINKER_LANGUAGE". Failure to follow
-this rule is not diagnosed and leaves the location of the target
-undefined.
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
+``(IMPLIB_)?(PREFIX|SUFFIX)``, or :prop_tgt:`LINKER_LANGUAGE`.
+Failure to follow this rule is not diagnosed and leaves
+the location of the target undefined.
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
new file mode 100644
index 000000000..6c6134197
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
@@ -0,0 +1,20 @@
+``MultiThreaded``
+ Compile with ``-MT`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDLL``
+ Compile with ``-MD`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+``MultiThreadedDebug``
+ Compile with ``-MTd`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDebugDLL``
+ Compile with ``-MDd`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+
+The value is ignored on non-MSVC compilers but an unsupported value will
+be rejected as an error when using a compiler targeting the MSVC ABI.
+
+The value may also be the empty string (``""``) in which case no runtime
+library selection flag will be added explicitly by CMake. Note that with
+:ref:`Visual Studio Generators` the native build system may choose to
+add its own default runtime library selection flag.
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 000000000..1e3f5e9ec
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,26 @@
+MSVC_RUNTIME_LIBRARY
+--------------------
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+
+The allowed values are:
+
+.. include:: MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ add_executable(foo foo.c)
+ set_property(TARGET foo PROPERTY
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for the target ``foo`` a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+.. note::
+
+ This property has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Help/prop_tgt/NO_SONAME.rst b/Help/prop_tgt/NO_SONAME.rst
index ee45ed849..d381a9c3b 100644
--- a/Help/prop_tgt/NO_SONAME.rst
+++ b/Help/prop_tgt/NO_SONAME.rst
@@ -1,10 +1,10 @@
NO_SONAME
---------
-Whether to set "soname" when linking a shared library.
+Whether to set ``soname`` when linking a shared library.
-Enable this boolean property if a generated shared library
-should not have "soname" set. Default is to set "soname" on all
+Enable this boolean property if a generated ``SHARED`` library
+should not have ``soname`` set. Default is to set ``soname`` on all
shared libraries as long as the platform supports it.
Generally, use this property only for leaf private libraries or
plugins. If you use it on normal shared libraries which other targets
diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
index 77fda9043..6c550831f 100644
--- a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -5,7 +5,8 @@ Per-configuration output directory for the MS debug symbol ``.pdb`` file
generated by the linker for an executable or shared library target.
This is a per-configuration version of :prop_tgt:`PDB_OUTPUT_DIRECTORY`,
-but multi-configuration generators (VS, Xcode) do NOT append a
+but multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable if it is
diff --git a/Help/prop_tgt/POST_INSTALL_SCRIPT.rst b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
index f1adb40b7..23935bcdf 100644
--- a/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
+++ b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
@@ -3,7 +3,7 @@ POST_INSTALL_SCRIPT
Deprecated install support.
-The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the old
-way to specify CMake scripts to run before and after installing a
-target. They are used only when the old INSTALL_TARGETS command is
-used to install the target. Use the INSTALL command instead.
+The :prop_tgt:`PRE_INSTALL_SCRIPT` and ``POST_INSTALL_SCRIPT`` properties are
+the old way to specify CMake scripts to run before and after installing a
+target. They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target. Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PREFIX.rst b/Help/prop_tgt/PREFIX.rst
index a16510461..a40129268 100644
--- a/Help/prop_tgt/PREFIX.rst
+++ b/Help/prop_tgt/PREFIX.rst
@@ -4,4 +4,4 @@ PREFIX
What comes before the library name.
A target property that can be set to override the prefix (such as
-"lib") on a library name.
+``lib``) on a library name.
diff --git a/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
index 113d7c56a..43432f4d8 100644
--- a/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
+++ b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
@@ -3,7 +3,7 @@ PRE_INSTALL_SCRIPT
Deprecated install support.
-The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the old
-way to specify CMake scripts to run before and after installing a
-target. They are used only when the old INSTALL_TARGETS command is
-used to install the target. Use the INSTALL command instead.
+The ``PRE_INSTALL_SCRIPT`` and :prop_tgt:`POST_INSTALL_SCRIPT` properties are
+the old way to specify CMake scripts to run before and after installing a
+target. They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target. Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PRIVATE_HEADER.rst b/Help/prop_tgt/PRIVATE_HEADER.rst
index 2bd4079fa..23e1f8e6f 100644
--- a/Help/prop_tgt/PRIVATE_HEADER.rst
+++ b/Help/prop_tgt/PRIVATE_HEADER.rst
@@ -8,4 +8,4 @@ frameworks on macOS, iOS and normal shared libraries on other platforms.
This property may be set to a list of header files to be placed in the
PrivateHeaders directory inside the framework folder. On non-Apple
platforms these headers may be installed using the ``PRIVATE_HEADER``
-option to the ``install(TARGETS)`` command.
+option to the :command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/PUBLIC_HEADER.rst b/Help/prop_tgt/PUBLIC_HEADER.rst
index 549ac7ce1..915e39cd2 100644
--- a/Help/prop_tgt/PUBLIC_HEADER.rst
+++ b/Help/prop_tgt/PUBLIC_HEADER.rst
@@ -8,4 +8,4 @@ frameworks on macOS, iOS and normal shared libraries on other platforms.
This property may be set to a list of header files to be placed in the
``Headers`` directory inside the framework folder. On non-Apple platforms
these headers may be installed using the ``PUBLIC_HEADER`` option to the
-``install(TARGETS)`` command.
+:command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/RESOURCE.rst b/Help/prop_tgt/RESOURCE.rst
index 55ae7740b..e5a1cb677 100644
--- a/Help/prop_tgt/RESOURCE.rst
+++ b/Help/prop_tgt/RESOURCE.rst
@@ -9,7 +9,7 @@ or normal shared libraries on other platforms.
This property may be set to a list of files to be placed in the corresponding
directory (eg. ``Resources`` directory for macOS) inside the bundle.
On non-Apple platforms these files may be installed using the ``RESOURCE``
-option to the ``install(TARGETS)`` command.
+option to the :command:`install(TARGETS)` command.
Following example of Application Bundle:
@@ -18,21 +18,18 @@ Following example of Application Bundle:
add_executable(ExecutableTarget
addDemo.c
resourcefile.txt
- appresourcedir/appres.txt
- )
+ appresourcedir/appres.txt)
target_link_libraries(ExecutableTarget heymath mul)
set(RESOURCE_FILES
resourcefile.txt
- appresourcedir/appres.txt
- )
+ appresourcedir/appres.txt)
set_target_properties(ExecutableTarget PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
- RESOURCE "${RESOURCE_FILES}"
- )
+ RESOURCE "${RESOURCE_FILES}")
will produce flat structure for iOS systems::
@@ -53,7 +50,7 @@ For macOS systems it will produce following directory structure::
appres.txt
resourcefile.txt
-For Linux, such cmake script produce following files::
+For Linux, such CMake script produce following files::
ExecutableTarget
Resources
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
index 94fb2776a..67277548e 100644
--- a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,8 @@ Per-configuration output directory for
This is a per-configuration version of the
:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target property, but
-multi-configuration generators (VS, Xcode) do NOT append a
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
diff --git a/Help/prop_tgt/SKIP_BUILD_RPATH.rst b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
index a91fa9ca3..7086b1bc4 100644
--- a/Help/prop_tgt/SKIP_BUILD_RPATH.rst
+++ b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
@@ -3,7 +3,7 @@ SKIP_BUILD_RPATH
Should rpaths be used for the build tree.
-SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic
+``SKIP_BUILD_RPATH`` is a boolean specifying whether to skip automatic
generation of an rpath allowing the target to run from the build tree.
This property is initialized by the value of the variable
-CMAKE_SKIP_BUILD_RPATH if it is set when a target is created.
+:variable:`CMAKE_SKIP_BUILD_RPATH` if it is set when a target is created.
diff --git a/Help/prop_tgt/SUFFIX.rst b/Help/prop_tgt/SUFFIX.rst
index 70844be5c..32ec42910 100644
--- a/Help/prop_tgt/SUFFIX.rst
+++ b/Help/prop_tgt/SUFFIX.rst
@@ -4,4 +4,4 @@ SUFFIX
What comes after the target name.
A target property that can be set to override the suffix (such as
-".so" or ".exe") on the name of a library, module or executable.
+``.so`` or ``.exe``) on the name of a library, module or executable.
diff --git a/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst b/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst
new file mode 100644
index 000000000..46c9a1d9b
--- /dev/null
+++ b/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst
@@ -0,0 +1,5 @@
+Swift_DEPENDENCIES_FILE
+-----------------------
+
+This property sets the path for the Swift dependency file (swiftdep) for the
+target. If one is not specified, it will default to ``<TARGET>.swiftdeps``.
diff --git a/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst b/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst
new file mode 100644
index 000000000..d40425166
--- /dev/null
+++ b/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst
@@ -0,0 +1,10 @@
+Swift_MODULE_DIRECTORY
+----------------------
+
+Specify output directory for Swift modules provided by the target.
+
+If the target contains Swift source files, this specifies the directory in which
+the modules will be placed. When this property is not set, the modules will be
+placed in the build directory corresponding to the target's source directory.
+If the variable :variable:`CMAKE_Swift_MODULE_DIRECTORY` is set when a target is
+created its value is used to initialise this property.
diff --git a/Help/prop_tgt/Swift_MODULE_NAME.rst b/Help/prop_tgt/Swift_MODULE_NAME.rst
new file mode 100644
index 000000000..28660203e
--- /dev/null
+++ b/Help/prop_tgt/Swift_MODULE_NAME.rst
@@ -0,0 +1,5 @@
+Swift_MODULE_NAME
+-----------------
+
+This property specifies the name of the Swift module. It is defaulted to the
+name of the target.
diff --git a/Help/prop_tgt/TYPE.rst b/Help/prop_tgt/TYPE.rst
index 1cd9db48f..3136d119d 100644
--- a/Help/prop_tgt/TYPE.rst
+++ b/Help/prop_tgt/TYPE.rst
@@ -4,6 +4,6 @@ TYPE
The type of the target.
This read-only property can be used to test the type of the given
-target. It will be one of STATIC_LIBRARY, MODULE_LIBRARY,
-SHARED_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY, EXECUTABLE or one
-of the internal target types.
+target. It will be one of ``STATIC_LIBRARY``, ``MODULE_LIBRARY``,
+``SHARED_LIBRARY``, ``OBJECT_LIBRARY``, ``INTERFACE_LIBRARY``, ``EXECUTABLE``
+or one of the internal target types.
diff --git a/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 000000000..42fb8ad86
--- /dev/null
+++ b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,10 @@
+VS_JUST_MY_CODE_DEBUGGING
+-------------------------
+
+Enable Just My Code with Visual Studio debugger.
+
+Supported on :ref:`Visual Studio Generators` for VS 2010 and higher,
+:ref:`Makefile Generators` and the :generator:`Ninja` generators.
+
+This property is initialized by the :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING`
+variable if it is set when a target is created.
diff --git a/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
new file mode 100644
index 000000000..ffcbde572
--- /dev/null
+++ b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
@@ -0,0 +1,46 @@
+VS_NO_SOLUTION_DEPLOY
+---------------------
+
+Specify that the target should not be marked for deployment to a Windows CE
+or Windows Phone device in the generated Visual Studio solution.
+
+Be default, all EXE and shared library (DLL) targets are marked to deploy to
+the target device in the generated Visual Studio solution.
+
+Generator expressions are supported.
+
+There are reasons one might want to exclude a target / generated project from
+deployment:
+
+- The library or executable may not be necessary in the primary deploy/debug
+ scenario, and excluding from deployment saves time in the
+ develop/download/debug cycle.
+- There may be insufficient space on the target device to accommodate all of
+ the build products.
+- Visual Studio 2013 requires a target device IP address be entered for each
+ target marked for deployment. For large numbers of targets, this can be
+ tedious.
+ NOTE: Visual Studio *will* deploy all project dependencies of a project
+ tagged for deployment to the IP address configured for that project even
+ if those dependencies are not tagged for deployment.
+
+
+Example 1
+^^^^^^^^^
+
+This shows setting the variable for the target foo.
+
+.. code-block:: cmake
+
+ add_library(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY ON)
+
+Example 2
+^^^^^^^^^
+
+This shows setting the variable for the Release configuration only.
+
+.. code-block:: cmake
+
+ add_library(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY "$<CONFIG:Release>")
diff --git a/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst b/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst
new file mode 100644
index 000000000..5a0465bcc
--- /dev/null
+++ b/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst
@@ -0,0 +1,13 @@
+VS_PACKAGE_REFERENCES
+---------------------
+
+Visual Studio package references for nuget.
+
+Adds one or more semicolon-delimited package references to a generated
+Visual Studio project. The version of the package will be
+underscore delimited. For example, ``boost_1.7.0;nunit_3.12.*``.
+
+.. code-block:: cmake
+
+ set_property(TARGET ${TARGET_NAME} PROPERTY
+ VS_PACKAGE_REFERENCES "boost_1.7.0")
diff --git a/Help/prop_tgt/VS_PROJECT_IMPORT.rst b/Help/prop_tgt/VS_PROJECT_IMPORT.rst
new file mode 100644
index 000000000..569c8ea74
--- /dev/null
+++ b/Help/prop_tgt/VS_PROJECT_IMPORT.rst
@@ -0,0 +1,8 @@
+VS_PROJECT_IMPORT
+-----------------
+
+Visual Studio managed project imports
+
+Adds to a generated Visual Studio project one or more semicolon-delimited paths
+to .props files needed when building projects from some NuGet packages.
+For example, ``my_packages_path/MyPackage.1.0.0/build/MyPackage.props``.
diff --git a/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
index 7e00ac430..71858c50e 100644
--- a/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
+++ b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
@@ -3,8 +3,8 @@ XCODE_ATTRIBUTE_<an-attribute>
Set Xcode target attributes directly.
-Tell the 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.
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_GENERATE_SCHEME.rst b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
new file mode 100644
index 000000000..0adb5dbea
--- /dev/null
+++ b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
@@ -0,0 +1,39 @@
+XCODE_GENERATE_SCHEME
+---------------------
+
+If enabled, the :generator:`Xcode` generator will generate schema files. These
+are useful to invoke analyze, archive, build-for-testing and test
+actions from the command line.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_GENERATE_SCHEME` if it is set when a target
+is created.
+
+The following target properties overwrite the default of the
+corresponding settings on the "Diagnostic" tab for each schema file.
+Each of those is initialized by the respective ``CMAKE_`` variable
+at target creation time.
+
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
+- :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
+- :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
+- :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
+
+The following target properties will be applied on the
+"Info" and "Arguments" tab:
+
+- :prop_tgt:`XCODE_SCHEME_ARGUMENTS`
+- :prop_tgt:`XCODE_SCHEME_DEBUG_AS_ROOT`
+- :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
+- :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
index 694cd7717..cc9bac2e6 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
index 2803da0b4..37a043a1a 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
if it is set when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
index 2eac4a926..1f228e34c 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
@@ -6,5 +6,5 @@ section of the generated Xcode scheme.
If set to a list of arguments those will be added to the scheme.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
new file mode 100644
index 000000000..5407e807b
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
@@ -0,0 +1,7 @@
+XCODE_SCHEME_DEBUG_AS_ROOT
+--------------------------
+
+Whether to debug the target as 'root'.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
index 75fc3262b..1a6fcfd2e 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
if it is set when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
index a7fab6677..922402290 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
index 162fc4576..203c80329 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
index 1dbd6c437..c6d875e88 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
@@ -8,5 +8,5 @@ If set to a list of environment variables and values of the form
``MYVAR=value`` those environment variables will be added to the
scheme.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
index d0427e266..104841b7c 100644
--- a/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
@@ -5,5 +5,5 @@ Specify path to executable in the Info section of the generated
Xcode scheme. If not set the schema generator will select the
current target if it is actually executable.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
index 64e1990eb..c4e83da2f 100644
--- a/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_GUARD_MALLOC` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
index 99c112fbc..73992c3c3 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -9,5 +9,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
index ef3852a35..ca761c05b 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
index 75baba2e0..c5ddb950f 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
index 984022c71..170f33d90 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_MALLOC_STACK` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
index 825ac5b30..bb70141f3 100644
--- a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
index 86f894ecc..5deadb16e 100644
--- a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
index 829a62ecd..0cd823dec 100644
--- a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
if it is set when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
index 5e382caca..d1a9bca2c 100644
--- a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -9,5 +9,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
if it is set when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
index 80b954a79..6e70e8be9 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -8,5 +8,5 @@ This property is initialized by the value of the variable
:variable:`CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS` if it is set
when a target is created.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/release/3.14.rst b/Help/release/3.14.rst
index 8a9738c84..229d8dc78 100644
--- a/Help/release/3.14.rst
+++ b/Help/release/3.14.rst
@@ -428,11 +428,3 @@ Changes made since CMake 3.14.0 include the following.
policy :policy:`CMP0088` ``NEW`` behavior accidentally interpreted
a relative path to the ``.y`` input as relative to the build tree
directory instead of the source tree directory. This has been fixed.
-
-3.14.7
-------
-
-* In CMake 3.14.0 through 3.14.6, the :prop_dir:`EXCLUDE_FROM_ALL`
- directory property was regressed from pre-3.14 behavior and caused
- targets within the directory to be excluded even from its own "all".
- This has been fixed.
diff --git a/Help/release/3.15.rst b/Help/release/3.15.rst
new file mode 100644
index 000000000..2cff419d9
--- /dev/null
+++ b/Help/release/3.15.rst
@@ -0,0 +1,347 @@
+CMake 3.15 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.14 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Xcode` generator now supports per-target schemes.
+ See the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable and
+ :prop_tgt:`XCODE_GENERATE_SCHEME` target property.
+
+* The :generator:`Green Hills MULTI` generator has been updated:
+
+ * It now supports the :command:`add_custom_command` and
+ :command:`add_custom_target` commands.
+
+ * It is now available on Linux.
+
+Languages
+---------
+
+* Preliminary support for the ``Swift`` language was added to the
+ :generator:`Ninja` generator:
+
+ * Use the :envvar:`SWIFTC` environment variable to specify a compiler.
+
+ * The :prop_tgt:`Swift_DEPENDENCIES_FILE` target property and
+ :prop_sf:`Swift_DEPENDENCIES_FILE` source file property were added
+ to customize dependency files.
+
+ * The :prop_tgt:`Swift_MODULE_NAME` target property was added to
+ customize the Swift module name.
+
+ * The :prop_sf:`Swift_DIAGNOSTICS_FILE` source property was added to
+ indicate where to write the serialised Swift diagnostics.
+
+ The Swift support is experimental, not considered stable, and may change
+ in future releases of CMake.
+
+Compilers
+---------
+
+* The ``Clang`` compiler variant on Windows that targets the MSVC ABI
+ but has a GNU-like command line is now supported.
+
+* Support for the Clang-based ARM compiler was added with compiler id
+ ``ARMClang``.
+
+* Support was added for the IAR compiler architectures Renesas RX,
+ RL78, RH850 and Texas Instruments MSP430.
+
+* Support was added for the IAR compilers built for Linux (IAR BuildLx).
+
+Command-Line
+------------
+
+* The :envvar:`CMAKE_GENERATOR` environment variable was added
+ to specify a default generator to use when :manual:`cmake(1)` is
+ run without a ``-G`` option. Additionally, environment variables
+ :envvar:`CMAKE_GENERATOR_PLATFORM`, :envvar:`CMAKE_GENERATOR_TOOLSET`,
+ and :envvar:`CMAKE_GENERATOR_INSTANCE` were created to configure
+ the generator.
+
+* The :manual:`cmake(1)` ``--build`` tool ``--target`` parameter gained support
+ for multiple targets, e.g. ``cmake --build . --target Library1 Library2``.
+ It now also has a short form ``-t`` alias, e.g.
+ ``cmake --build . -t Library1 Library2``.
+
+* The :manual:`cmake(1)` command gained a new ``--install`` option.
+ This may be used after building a project to run installation without
+ using the generated build system or the native build tool.
+
+* The :manual:`cmake(1)` command learned a new CLI option ``--loglevel``.
+
+* The :manual:`cmake(1)` ``-E remove_directory`` command-line tool learned
+ to support removing multiple directories.
+
+* The :manual:`cmake(1)` ``-E tar`` tool has been improved:
+
+ * It now continues adding files to an archive even if some of the files
+ are not readable. This behavior is more consistent with the
+ classic ``tar`` tool.
+
+ * It now parses all flags, and if an invalid flag was provided, a
+ warning is issued.
+
+ * It now displays an error if no action flag was specified, along with a
+ list of possible actions: ``t`` (list), ``c`` (create) or ``x`` (extract).
+
+ * It now supports extracting (``-x``) or listing (``-t``) only specific
+ files or directories.
+
+ * It now supports Zstandard compression with a ``--zstd`` option.
+ Zstandard was designed to give a compression ratio comparable to that
+ of the DEFLATE (zip) algorithm, but faster, especially for decompression.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ gained a new ``JOB_POOL`` option that works with the :generator:`Ninja`
+ generator to set the pool variable on the build statement.
+
+* The :command:`add_library` command ``ALIAS`` option learned to support
+ import libraries of the ``UNKNOWN`` type.
+
+* The :command:`cmake_parse_arguments` command gained an additional
+ ``<prefix>_KEYWORDS_MISSING_VALUES`` output variable to report
+ keyword arguments that were given by the caller with no values.
+
+* The :command:`execute_process` command gained a ``COMMAND_ECHO`` option
+ and supporting :variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ECHO` variable
+ to enable echoing of the command-line string before execution.
+
+* The :command:`file(INSTALL)` command learned a new argument,
+ ``FOLLOW_SYMLINK_CHAIN``, which can be used to recursively resolve and
+ install symlinks.
+
+* :command:`list` learned new sub-commands:
+ ``PREPEND``, ``POP_FRONT`` and ``POP_BACK``.
+
+* The :command:`message` command learned new types:
+ ``NOTICE``, ``VERBOSE``, ``DEBUG`` and ``TRACE``.
+
+* The :command:`string` learned a new sub-command ``REPEAT``.
+
+Variables
+---------
+
+* The :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable and corresponding
+ :prop_tgt:`CROSSCOMPILING_EMULATOR` target property learned to support
+ arguments to the emulator.
+
+* The :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` variable was added to tell
+ :command:`find_package` calls to look for a package configuration
+ file first even if a find module is available.
+
+* The :variable:`CMAKE_FRAMEWORK` variable was added to initialize the
+ :prop_tgt:`FRAMEWORK` property on all targets.
+
+* The :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING` variable and
+ :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING` target property were added to
+ enable the Just My Code feature of the Visual Studio Debugger when
+ compiling with MSVC cl 19.05 and higher.
+
+* The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` variable and
+ :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property were introduced to
+ select the runtime library used by compilers targeting the MSVC ABI.
+ See policy :policy:`CMP0091`.
+
+* The :variable:`CMAKE_PROJECT_INCLUDE` and
+ :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables were added to allow
+ injection of custom code at the sites of :command:`project` calls
+ without knowing the project name a priori.
+
+Properties
+----------
+
+* The :prop_tgt:`ADDITIONAL_CLEAN_FILES` target property and
+ :prop_dir:`ADDITIONAL_CLEAN_FILES` directory property were added.
+ They allow to register additional files that should be removed during
+ the clean stage.
+
+* The :prop_tgt:`PUBLIC_HEADER` and :prop_tgt:`PRIVATE_HEADER` properties
+ may now be set on :ref:`Interface Libraries`. The headers specified by those
+ properties can be installed using the :command:`install(TARGETS)` command by
+ passing the ``PUBLIC_HEADER`` and ``PRIVATE_HEADER`` arguments respectively.
+
+* The :prop_tgt:`VS_PACKAGE_REFERENCES` target property was added to
+ tell :ref:`Visual Studio Generators` to add references to ``nuget``
+ packages.
+
+* The :prop_tgt:`VS_PROJECT_IMPORT` target property was added to allow
+ managed Visual Studio project files to import external ``.props`` files.
+
+* The :prop_tgt:`VS_NO_SOLUTION_DEPLOY` target property was added to
+ tell :ref:`Visual Studio Generators` whether to deploy an artifact
+ to the WinCE or Windows Phone target device.
+
+Modules
+-------
+
+* The :module:`FindBoost` module was reworked to expose a more consistent
+ user experience between its "Config" and "Module" modes and with other
+ find modules in general.
+
+ * A new imported target ``Boost::headers`` is now defined (same
+ as ``Boost::boost``).
+
+ * New output variables ``Boost_VERSION_MACRO``,
+ ``Boost_VERSION_MAJOR``, ``Boost_VERSION_MINOR``,
+ ``Boost_VERSION_PATCH``, and ``Boost_VERSION_COUNT``
+ were added.
+
+ * The ``QUIET`` argument passed to :command:`find_package` is no
+ longer ignored in config mode. Note that the CMake package shipped with
+ Boost ``1.70.0`` ignores the ``QUIET`` argument passed to
+ :command:`find_package`. This is fixed in the next Boost release.
+
+ * The input switch ``Boost_DETAILED_FAILURE_MSG`` was removed.
+
+ * ``Boost_VERSION`` now reports the version in ``x.y.z``
+ format in module mode. See policy :policy:`CMP0093`.
+
+* The :module:`FindCups` module now provides imported targets.
+
+* The :module:`FindEnvModules` module was added to use Lua- and TCL-based
+ environment modules in :ref:`CTest Scripts <CTest Script>`.
+
+* The :module:`FindGLEW` module now provides an interface more consistent
+ with what upstream GLEW provides in its own CMake package files.
+
+* The :module:`FindPkgConfig` now populates :prop_tgt:`INTERFACE_LINK_OPTIONS`
+ property of imported targets with other (non-library) linker flags.
+
+* The :module:`FindPostgreSQL` module learned to find debug and release
+ variants separately.
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gained additional lookup strategies and controls, and a new default.
+ See policy :policy:`CMP0094`.
+
+* Modules :module:`FindPython`, :module:`FindPython2` and :module:`FindPython3`
+ gain a new target (respectively ``Python::Module``, ``Python2::Module``
+ and ``Python3::Module``) which can be used to develop Python modules.
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gain capability to control how virtual environments are handled.
+
+* The :module:`UseSWIG` module learned to manage alternate library names
+ by passing ``-interface <library_name>`` for ``python`` language or
+ ``-dllimport <library_name>`` for ``CSharp`` language to the ``SWIG``
+ compiler.
+
+Generator Expressions
+---------------------
+
+* The :manual:`generator expressions <cmake-generator-expressions(7)>`
+ ``C_COMPILER_ID``, ``CXX_COMPILER_ID``, ``CUDA_COMPILER_ID``,
+ ``Fortran_COMPILER_ID``, ``COMPILE_LANGUAGE``, ``COMPILE_LANG_AND_ID``, and
+ ``PLATFORM_ID`` learned to support matching one value from a comma-separated
+ list.
+
+* The ``$<CUDA_COMPILER_ID:...>`` and ``$<CUDA_COMPILER_VERSION:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>` were added.
+
+* The ``$<COMPILE_LANG_AND_ID:...>`` generator expression was introduced to
+ allow specification of compile options for target files based on the
+ :variable:`CMAKE_<LANG>_COMPILER_ID` and :prop_sf:`LANGUAGE` of
+ each source file.
+
+* A ``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* A ``$<REMOVE_DUPLICATES:list>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* The ``$<SHELL_PATH:...>`` :manual:`generator expression
+ <cmake-generator-expressions(7)>` gained support for a list of paths.
+
+* New ``$<TARGET_FILE*>`` :manual:`generator expressions
+ <cmake-generator-expressions(7)>` were added to retrieve the prefix, base
+ name, and suffix of the file names of various artifacts:
+
+ * ``$<TARGET_FILE_PREFIX:...>``
+ * ``$<TARGET_FILE_BASE_NAME:...>``
+ * ``$<TARGET_FILE_SUFFIX:...>``
+ * ``$<TARGET_LINKER_FILE_PREFIX:...>``
+ * ``$<TARGET_LINKER_FILE_BASE_NAME:...>``
+ * ``$<TARGET_LINKER_FILE_SUFFIX:...>``
+ * ``$<TARGET_PDB_FILE_BASE_NAME:...>``
+
+* The ``$<TARGET_OBJECTS:...>`` :manual:`generator expression
+ <cmake-generator-expressions(7)>` is now supported on ``SHARED``,
+ ``STATIC``, ``MODULE`` libraries and executables.
+
+CTest
+-----
+
+* The :command:`ctest_submit` command learned a new option: ``BUILD_ID``.
+ This can be used to store the ID assigned to this build by CDash to a
+ variable.
+
+* The :command:`ctest_update` command learned to honor a new variable:
+ :variable:`CTEST_UPDATE_VERSION_OVERRIDE`. This can be used to specify
+ the current version of your source tree rather than using the update
+ command to discover the current version that is checked out.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack IFW Generator` gained a new
+ :variable:`CPACK_IFW_PACKAGE_STYLE_SHEET` variable to customize the
+ installer stylesheet.
+
+Deprecated and Removed Features
+===============================
+
+* The :manual:`cmake-server(7)` mode has been deprecated and will be
+ removed from a future version of CMake. Please port clients to use
+ the :manual:`cmake-file-api(7)` instead.
+
+* The :prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES` directory property is now
+ deprecated. Use the :prop_dir:`ADDITIONAL_CLEAN_FILES` directory property
+ instead.
+
+* The variable :variable:`CMAKE_AUTOMOC_RELAXED_MODE` is considered
+ deprecated. Support still exists but will be removed in future versions.
+
+* The :command:`export(PACKAGE)` command now does nothing unless
+ enabled via :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY`.
+ See policy :policy:`CMP0090`.
+
+* The :generator:`Xcode` generator now requires at least Xcode 5.
+
+* An explicit deprecation diagnostic was added for policy ``CMP0066``
+ (``CMP0065`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+Other Changes
+=============
+
+* CMake learned how to compile C++14 with the IBM AIX XL compiler
+ and the SunPro compiler and to compile C++20 with the AppleClang compiler.
+
+* With MSVC-like compilers the value of :variable:`CMAKE_<LANG>_FLAGS`
+ no longer contains warning flags like ``/W3`` by default.
+ See policy :policy:`CMP0092`.
+
+* IBM Clang-based XL compilers that define ``__ibmxl__`` now use the
+ compiler id ``XLClang`` instead of ``XL``. See policy :policy:`CMP0089`.
+
+* The :command:`file(REMOVE)` and :command:`file(REMOVE_RECURSE)` commands
+ were changed to ignore empty arguments with a warning instead of treating
+ them as a relative path and removing the contents of the current directory.
diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst
index ffa95aa27..89da62751 100644
--- a/Help/release/3.9.rst
+++ b/Help/release/3.9.rst
@@ -150,7 +150,7 @@ Modules
* The :module:`CMakeFindDependencyMacro` module ``find_dependency`` macro
now forwards all arguments to the underlying :command:`find_package`
call. Existing uses will continue to function as before, but callers can
- now access the full suite of arguments that ``find_package`` accepts.
+ now access the full suite of arguments that :command:`find_package` accepts.
* The :module:`FeatureSummary` module :command:`feature_summary` command now
accepts the new ``DEFAULT_DESCRIPTION`` option that will print the default
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 4fcd4ca4f..35a47aa67 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -13,6 +13,7 @@ Releases
.. toctree::
:maxdepth: 1
+ 3.15 <3.15>
3.14 <3.14>
3.13 <3.13>
3.12 <3.12>
diff --git a/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
index addc62de4..6c0c61b11 100644
--- a/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
+++ b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
@@ -1,6 +1,8 @@
CMAKE_AUTOMOC_RELAXED_MODE
--------------------------
+.. deprecated:: 3.15
+
Switch between strict and relaxed automoc mode.
By default, :prop_tgt:`AUTOMOC` behaves exactly as described in the
diff --git a/Help/variable/CMAKE_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst
index 9e96769a7..7e6ec3371 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING.rst
@@ -19,8 +19,9 @@ macOS are handled differently to other cross compiling scenarios. Rather than
relying on :variable:`CMAKE_SYSTEM_NAME` to select the target platform, Apple
device builds use :variable:`CMAKE_OSX_SYSROOT` to select the appropriate SDK,
which indirectly determines the target platform. Furthermore, when using the
-Xcode generator, developers can switch between device and simulator builds at
-build time rather than having a single choice at configure time, so the concept
+:generator:`Xcode` generator, developers can switch between device and
+simulator builds at build time rather than having a single
+choice at configure time, so the concept
of whether the build is cross compiling or not is more complex. Therefore, the
use of ``CMAKE_CROSSCOMPILING`` is not recommended for projects targeting Apple
devices.
diff --git a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
index 95d2c7ffc..1d013b7a6 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
@@ -5,8 +5,12 @@ This variable is only used when :variable:`CMAKE_CROSSCOMPILING` is on. It
should point to a command on the host system that can run executable built
for the target system.
+If this variable contains a :ref:`semicolon-separated list <CMake Language
+Lists>`, then the first value is the command and remaining values are its
+arguments.
+
The command will be used to run :command:`try_run` generated executables,
-which avoids manual population of the TryRunResults.cmake file.
+which avoids manual population of the ``TryRunResults.cmake`` file.
It is also used as the default value for the
:prop_tgt:`CROSSCOMPILING_EMULATOR` target property of executables.
diff --git a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
index 72e8e66ac..eea2c4fbd 100644
--- a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
+++ b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
@@ -2,6 +2,6 @@ CMAKE_CUDA_HOST_COMPILER
------------------------
Executable to use when compiling host code when compiling ``CUDA`` language
-files. Maps to the nvcc -ccbin option. Will only be used by CMake on the first
+files. Maps to the ``nvcc -ccbin`` option. Will only be used by CMake on the first
configuration to determine a valid host compiler for ``CUDA``. After a valid
host compiler has been found, this value is read-only.
diff --git a/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst
new file mode 100644
index 000000000..76561d82b
--- /dev/null
+++ b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst
@@ -0,0 +1,6 @@
+CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+----------------------------------
+
+If this variable is set to ``STDERR``, ``STDOUT`` or ``NONE`` then commands
+in :command:`execute_process` calls will be printed to either stderr or
+stdout or not at all.
diff --git a/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
index ee109ba1a..768ed64bf 100644
--- a/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
+++ b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
@@ -1,11 +1,16 @@
CMAKE_EXPORT_NO_PACKAGE_REGISTRY
--------------------------------
-Disable the :command:`export(PACKAGE)` command.
+Disable the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is not set to ``NEW``.
In some cases, for example for packaging and for system wide
installations, it is not desirable to write the user package registry.
-If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable is enabled,
+If the ``CMAKE_EXPORT_NO_PACKAGE_REGISTRY`` variable is enabled,
the :command:`export(PACKAGE)` command will do nothing.
+If :policy:`CMP0090` is set to ``NEW`` this variable does nothing, and the
+:variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
new file mode 100644
index 000000000..3476a199c
--- /dev/null
+++ b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
@@ -0,0 +1,15 @@
+CMAKE_EXPORT_PACKAGE_REGISTRY
+-----------------------------
+
+Enables the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is set to ``NEW``.
+
+The :command:`export(PACKAGE)` command does nothing by default. In some cases
+it is desirable to write to the user package registry, so the
+``CMAKE_EXPORT_PACKAGE_REGISTRY`` variable may be set to enable it.
+
+If :policy:`CMP0090` is *not* set to ``NEW`` this variable does nothing, and
+the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst
new file mode 100644
index 000000000..db658a1e0
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst
@@ -0,0 +1,27 @@
+CMAKE_FIND_PACKAGE_PREFER_CONFIG
+---------------------------------
+
+Tell :command:`find_package` to try "Config" mode before "Module" mode if no
+mode was specified.
+
+The command :command:`find_package` operates without an explicit mode when
+the reduced signature is used without the ``MODULE`` option. In this case,
+by default, CMake first tries Module mode by searching for a
+``Find<pkg>.cmake`` module. If it fails, CMake then searches for the package
+using Config mode.
+
+Set ``CMAKE_FIND_PACKAGE_PREFER_CONFIG`` to ``TRUE`` to tell
+:command:`find_package` to first search using Config mode before falling back
+to Module mode.
+
+This variable may be useful when a developer has compiled a custom version of
+a common library and wishes to link it to a dependent project. If this
+variable is set to ``TRUE``, it would prevent a dependent project's call
+to :command:`find_package` from selecting the default library located by the
+system's ``Find<pkg>.cmake`` module before finding the developer's custom
+built library.
+
+Once this variable is set, it is the responsibility of the exported
+``<pkg>Config.cmake`` files to provide the same result variables as the
+``Find<pkg>.cmake`` modules so that dependent projects can use them
+interchangeably.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
index f1116bb62..5c4f23a4a 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
@@ -17,3 +17,6 @@ Set ``CMAKE_FIND_PACKAGE_WARN_NO_MODULE`` to ``TRUE`` to tell
:command:`find_package` to warn when it implicitly assumes Config mode. This
helps developers enforce use of an explicit mode in all calls to
:command:`find_package` within a project.
+
+This variable has no effect if :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` is
+set to ``TRUE``.
diff --git a/Help/variable/CMAKE_FRAMEWORK.rst b/Help/variable/CMAKE_FRAMEWORK.rst
new file mode 100644
index 000000000..591041c8b
--- /dev/null
+++ b/Help/variable/CMAKE_FRAMEWORK.rst
@@ -0,0 +1,7 @@
+CMAKE_FRAMEWORK
+---------------
+
+Default value for :prop_tgt:`FRAMEWORK` of targets.
+
+This variable is used to initialize the :prop_tgt:`FRAMEWORK` property on
+all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_GENERATOR.rst b/Help/variable/CMAKE_GENERATOR.rst
index cce04c136..ec52cd4d8 100644
--- a/Help/variable/CMAKE_GENERATOR.rst
+++ b/Help/variable/CMAKE_GENERATOR.rst
@@ -5,3 +5,8 @@ The generator used to build the project. See :manual:`cmake-generators(7)`.
The name of the generator that is being used to generate the build
files. (e.g. ``Unix Makefiles``, ``Ninja``, etc.)
+
+The value of this variable should never be modified by project code.
+A generator may be selected via the :manual:`cmake(1)` ``-G`` option,
+interactively in :manual:`cmake-gui(1)`, or via the :envvar:`CMAKE_GENERATOR`
+environment variable.
diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
index 78c81b1a3..3657ed4ff 100644
--- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
+++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
@@ -5,9 +5,10 @@ Generator-specific instance specification provided by user.
Some CMake generators support selection of an instance of the native build
system when multiple instances are available. If the user specifies an
-instance (e.g. by setting this cache entry), or after a default instance is
-chosen when a build tree is first configured, the value will be available in
-this variable.
+instance (e.g. by setting this cache entry or via the
+:envvar:`CMAKE_GENERATOR_INSTANCE` environment variable), or after a default
+instance is chosen when a build tree is first configured, the value will be
+available in this variable.
The value of this variable should never be modified by project code.
A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
index 963f0a479..2c115a3ab 100644
--- a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
+++ b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
@@ -6,7 +6,8 @@ Generator-specific target platform specification provided by user.
Some CMake generators support a target platform name to be given
to the native build system to choose a compiler toolchain.
If the user specifies a platform name (e.g. via the :manual:`cmake(1)` ``-A``
-option) the value will be available in this variable.
+option or via the :envvar:`CMAKE_GENERATOR_PLATFORM` environment variable)
+the value will be available in this variable.
The value of this variable should never be modified by project code.
A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
index e77f211dd..a01a8b72c 100644
--- a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -5,7 +5,8 @@ Native build system toolset specification provided by user.
Some CMake generators support a toolset specification to tell the
native build system how to choose a compiler. If the user specifies
-a toolset (e.g. via the :manual:`cmake(1)` ``-T`` option) the value
+a toolset (e.g. via the :manual:`cmake(1)` ``-T`` option or via
+the :envvar:`CMAKE_GENERATOR_TOOLSET` environment variable) the value
will be available in this variable.
The value of this variable should never be modified by project code.
diff --git a/Help/variable/CMAKE_JOB_POOL_LINK.rst b/Help/variable/CMAKE_JOB_POOL_LINK.rst
index 338f7714e..eeee6e069 100644
--- a/Help/variable/CMAKE_JOB_POOL_LINK.rst
+++ b/Help/variable/CMAKE_JOB_POOL_LINK.rst
@@ -1,5 +1,5 @@
CMAKE_JOB_POOL_LINK
-----------------------
+-------------------
This variable is used to initialize the :prop_tgt:`JOB_POOL_LINK`
property on all the targets. See :prop_tgt:`JOB_POOL_LINK`
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
index 5323880d5..8eb4fb612 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_ID.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
@@ -12,6 +12,7 @@ include:
ADSP = Analog VisualDSP++ (analog.com)
AppleClang = Apple Clang (apple.com)
ARMCC = ARM Compiler (arm.com)
+ ARMClang = ARM Compiler based on Clang (arm.com)
Bruce = Bruce C Compiler
CCur = Concurrent Fortran (ccur.com)
Clang = LLVM Clang (clang.llvm.org)
@@ -24,7 +25,6 @@ include:
HP = Hewlett-Packard Compiler (hp.com)
IAR = IAR Systems (iar.com)
Intel = Intel Compiler (intel.com)
- MIPSpro = SGI MIPSpro (sgi.com)
MSVC = Microsoft Visual Studio (microsoft.com)
NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
OpenWatcom = Open Watcom (openwatcom.org)
@@ -35,6 +35,7 @@ include:
TI = Texas Instruments (ti.com)
TinyCC = Tiny C Compiler (tinycc.org)
XL, VisualAge, zOS = IBM XL (ibm.com)
+ XLClang = IBM Clang-based XL (ibm.com)
This variable is not guaranteed to be defined for all compilers or
languages.
diff --git a/Help/variable/CMAKE_MAKE_PROGRAM.rst b/Help/variable/CMAKE_MAKE_PROGRAM.rst
index 4f5a50fae..a3c8b7c8a 100644
--- a/Help/variable/CMAKE_MAKE_PROGRAM.rst
+++ b/Help/variable/CMAKE_MAKE_PROGRAM.rst
@@ -19,15 +19,11 @@ to configure the project:
This generator stores ``CMAKE_MAKE_PROGRAM`` in the CMake cache
so that it may be edited by the user.
-* The :generator:`Xcode` generator sets this to ``xcodebuild`` (or possibly an
- otherwise undocumented ``cmakexbuild`` wrapper implementing some
- workarounds).
+* The :generator:`Xcode` generator sets this to ``xcodebuild``.
This generator prefers to lookup the build tool at build time
rather than to store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
- ahead of time. This is because ``xcodebuild`` is easy to find,
- the ``cmakexbuild`` wrapper is needed only for older Xcode versions,
- and the path to ``cmakexbuild`` may be outdated if CMake itself moves.
+ ahead of time. This is because ``xcodebuild`` is easy to find.
For compatibility with versions of CMake prior to 3.2, if
a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
@@ -56,7 +52,8 @@ to configure the project:
possible.
* The :generator:`Green Hills MULTI` generator sets this to the full
- path to ``gbuild.exe`` based upon the toolset being used.
+ path to ``gbuild.exe(Windows)`` or ``gbuild(Linux)`` based upon
+ the toolset being used.
Once the generator has initialized a particular value for this
variable, changing the value has undefined behavior.
diff --git a/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 000000000..6ed68c919
--- /dev/null
+++ b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,27 @@
+CMAKE_MSVC_RUNTIME_LIBRARY
+--------------------------
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+This variable is used to initialize the :prop_tgt:`MSVC_RUNTIME_LIBRARY`
+property on all targets as they are created. It is also propagated by
+calls to the :command:`try_compile` command into the test project.
+
+The allowed values are:
+
+.. include:: ../prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for all following targets a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+.. note::
+
+ This variable has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
index d17972873..fc52e7b5d 100644
--- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -21,6 +21,8 @@ warn by default:
policy :policy:`CMP0067`.
* ``CMAKE_POLICY_WARNING_CMP0082`` controls the warning for
policy :policy:`CMP0082`.
+* ``CMAKE_POLICY_WARNING_CMP0089`` controls the warning for
+ policy :policy:`CMP0089`.
This variable should not be set by a project in CMake code. Project
developers running CMake may set this variable in their cache to
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
new file mode 100644
index 000000000..965c94ee7
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
@@ -0,0 +1,9 @@
+CMAKE_PROJECT_INCLUDE
+---------------------
+
+A CMake language file or module to be included as the last step of all
+:command:`project` command calls. This is intended for injecting custom code
+into project builds without modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
new file mode 100644
index 000000000..70b15e662
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
@@ -0,0 +1,9 @@
+CMAKE_PROJECT_INCLUDE_BEFORE
+----------------------------
+
+A CMake language file or module to be included as the first step of all
+:command:`project` command calls. This is intended for injecting custom code
+into project builds without modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
index 5ca40a361..3485c38e4 100644
--- a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
+++ b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
@@ -1,6 +1,10 @@
CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE
------------------------------------
-A CMake language file or module to be included by the :command:`project`
-command. This is intended for injecting custom code into project
-builds without modifying their source.
+A CMake language file or module to be included as the last step of any
+:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
+name. This is intended for injecting custom code into project builds without
+modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
index 44966f32f..b77bb686a 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
@@ -3,6 +3,6 @@ CMAKE_SKIP_INSTALL_RULES
Whether to disable generation of installation rules.
-If ``TRUE``, cmake will neither generate installaton rules nor
+If ``TRUE``, CMake will neither generate installation rules nor
will it generate ``cmake_install.cmake`` files. This variable is ``FALSE`` by
default.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index 416fbe1a8..d1f179838 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -7,7 +7,7 @@ This is the full path to the top level of the current CMake source
tree. For an in-source build, this would be the same as
:variable:`CMAKE_BINARY_DIR`.
-When run in -P script mode, CMake sets the variables
+When run in ``-P`` script mode, CMake sets the variables
:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
:variable:`CMAKE_CURRENT_BINARY_DIR` and
:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_STAGING_PREFIX.rst b/Help/variable/CMAKE_STAGING_PREFIX.rst
index 1310e9471..bdb97faef 100644
--- a/Help/variable/CMAKE_STAGING_PREFIX.rst
+++ b/Help/variable/CMAKE_STAGING_PREFIX.rst
@@ -5,10 +5,10 @@ This variable may be set to a path to install to when cross-compiling. This can
be useful if the path in :variable:`CMAKE_SYSROOT` is read-only, or otherwise
should remain pristine.
-The ``CMAKE_STAGING_PREFIX`` location is also used as a search prefix by the
-``find_*`` commands. This can be controlled by setting the
+The :variable:`CMAKE_STAGING_PREFIX` location is also used as a search prefix
+by the ``find_*`` commands. This can be controlled by setting the
:variable:`CMAKE_FIND_NO_INSTALL_PREFIX` variable.
-If any RPATH/RUNPATH entries passed to the linker contain the
-``CMAKE_STAGING_PREFIX``, the matching path fragments are replaced with the
-:variable:`CMAKE_INSTALL_PREFIX`.
+If any ``RPATH``/``RUNPATH`` entries passed to the linker contain the
+:variable:`CMAKE_STAGING_PREFIX`, the matching path fragments are replaced
+with the :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
index ed47e1aea..96184dd5e 100644
--- a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
+++ b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
@@ -1,10 +1,10 @@
CMAKE_SUPPRESS_REGENERATION
---------------------------
-If CMAKE_SUPPRESS_REGENERATION is ``OFF``, which is default, then CMake adds a
-special target on which all other targets depend that checks the build system
-and optionally re-runs CMake to regenerate the build system when the target
-specification source changes.
+If ``CMAKE_SUPPRESS_REGENERATION`` is ``OFF``, which is default, then CMake
+adds a special target on which all other targets depend that checks the build
+system and optionally re-runs CMake to regenerate the build system when
+the target specification source changes.
If this variable evaluates to ``ON`` at the end of the top-level
``CMakeLists.txt`` file, CMake will not add the regeneration target to the
diff --git a/Help/variable/CMAKE_SYSROOT.rst b/Help/variable/CMAKE_SYSROOT.rst
index 64f81bbc2..35b944fa4 100644
--- a/Help/variable/CMAKE_SYSROOT.rst
+++ b/Help/variable/CMAKE_SYSROOT.rst
@@ -4,8 +4,8 @@ CMAKE_SYSROOT
Path to pass to the compiler in the ``--sysroot`` flag.
The ``CMAKE_SYSROOT`` content is passed to the compiler in the ``--sysroot``
-flag, if supported. The path is also stripped from the RPATH/RUNPATH if
-necessary on installation. The ``CMAKE_SYSROOT`` is also used to prefix
+flag, if supported. The path is also stripped from the ``RPATH``/``RUNPATH``
+if necessary on installation. The ``CMAKE_SYSROOT`` is also used to prefix
paths searched by the ``find_*`` commands.
This variable may only be set in a toolchain file specified by
diff --git a/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst b/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst
new file mode 100644
index 000000000..b11253bc1
--- /dev/null
+++ b/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst
@@ -0,0 +1,8 @@
+CMAKE_Swift_MODULE_DIRECTORY
+----------------------------
+
+Swift module output directory.
+
+This variable is used to initialise the :prop_tgt:`Swift_MODULE_DIRECTORY`
+property on all the targets. See the target property for additional
+information.
diff --git a/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 000000000..546cdf492
--- /dev/null
+++ b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,8 @@
+CMAKE_VS_JUST_MY_CODE_DEBUGGING
+-------------------------------
+
+Enable Just My Code with Visual Studio debugger.
+
+This variable is used to initialize the :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING`
+property on all targets when they are created. See that target property for
+additional information.
diff --git a/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
index 74667845d..5b1a003f0 100644
--- a/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
+++ b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
@@ -1,34 +1,10 @@
CMAKE_XCODE_GENERATE_SCHEME
---------------------------
-If enabled, the Xcode generator will generate schema files. These
+If enabled, the :generator:`Xcode` generator will generate schema files. These
are useful to invoke analyze, archive, build-for-testing and test
actions from the command line.
-The following target properties overwrite the default of the
-corresponding settings on the "Diagnostic" tab for each schema file.
-Each of those is initialized by the respective ``CMAKE_`` variable
-at target creation time.
-
-- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
-- :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
-- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
-- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
-- :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
-- :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
-- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
-- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
-- :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
-
-The following target properties will be applied on the
-"Info" and "Arguments" tab:
-
-- :prop_tgt:`XCODE_SCHEME_ARGUMENTS`
-- :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
-- :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
+This variable initializes the
+:prop_tgt:`XCODE_GENERATE_SCHEME`
+target property on all targets.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
index 37dc0ce80..b972ba573 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
index 05949c3a8..59eb32df3 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
index 81f49745a..71bcf4235 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
index 5e133ac1f..53f55e604 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
index 33162d97e..784ceb6b7 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
index 03d88c232..9350244b0 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
index fd6135f29..45a2dad69 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -9,5 +9,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
index 8fedc20f3..94d1c61fb 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
index cddca7c97..9bf0eb419 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
index 9c83698f8..4cc21ee2b 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
index c9373697e..6d1b56eea 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
index eed796cc9..de40478ea 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
index d14ba3f81..ec5df6613 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
index f8df30473..dcec9b0ea 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -9,5 +9,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
index efc331a17..82e9d76cc 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -8,5 +8,5 @@ This variable initializes the
:prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
property on all targets.
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index 5dad6bd68..30ae23638 100644
--- a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -5,7 +5,7 @@ Ask CPack to error out as soon as a file with absolute ``INSTALL DESTINATION``
is encountered.
The fatal error is emitted before the installation of the offending
-file takes place. Some CPack generators, like NSIS, enforce this
+file takes place. Some CPack generators, like ``NSIS``, enforce this
internally. This variable triggers the definition
of :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack
runs.
diff --git a/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst b/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst
index 36fa37d92..a03d47342 100644
--- a/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst
+++ b/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst
@@ -2,6 +2,6 @@ CTEST_CUSTOM_WARNING_EXCEPTION
------------------------------
A list of regular expressions which will be used to exclude when detecting
-warning messages in build outputs by the :command:`ctest_test` command.
+warning messages in build outputs by the :command:`ctest_build` command.
.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst b/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst
index a35be96b5..18aa6b31d 100644
--- a/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst
+++ b/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst
@@ -2,6 +2,6 @@ CTEST_CUSTOM_WARNING_MATCH
--------------------------
A list of regular expressions which will be used to detect warning messages in
-build outputs by the :command:`ctest_test` command.
+build outputs by the :command:`ctest_build` command.
.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
index e646e6eea..a862baa14 100644
--- a/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
+++ b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
@@ -1,5 +1,5 @@
CTEST_UPDATE_VERSION_ONLY
-------------------------
-Specify the CTest ``UpdateVersionOnly`` setting
+Specify the CTest :ref:`UpdateVersionOnly <UpdateVersionOnly>` setting
in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
new file mode 100644
index 000000000..39fbaba79
--- /dev/null
+++ b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
@@ -0,0 +1,5 @@
+CTEST_UPDATE_VERSION_OVERRIDE
+-----------------------------
+
+Specify the CTest :ref:`UpdateVersionOverride <UpdateVersionOverride>` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/PackageName_ROOT.rst b/Help/variable/PackageName_ROOT.rst
index c5b07ae2b..1c2fd34f3 100644
--- a/Help/variable/PackageName_ROOT.rst
+++ b/Help/variable/PackageName_ROOT.rst
@@ -3,7 +3,7 @@
Calls to :command:`find_package(<PackageName>)` will search in prefixes
specified by the ``<PackageName>_ROOT`` CMake variable, where
-``<PackageName>`` is the name given to the ``find_package`` call
+``<PackageName>`` is the name given to the :command:`find_package` call
and ``_ROOT`` is literal. For example, ``find_package(Foo)`` will search
prefixes specified in the ``Foo_ROOT`` CMake variable (if set).
See policy :policy:`CMP0074`.
diff --git a/Help/variable/XCODE_VERSION.rst b/Help/variable/XCODE_VERSION.rst
index b85d41e91..9caf19a41 100644
--- a/Help/variable/XCODE_VERSION.rst
+++ b/Help/variable/XCODE_VERSION.rst
@@ -3,5 +3,5 @@ XCODE_VERSION
Version of Xcode (:generator:`Xcode` generator only).
-Under the Xcode generator, this is the version of Xcode as specified
-in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
+Under the :generator:`Xcode` generator, this is the version of Xcode
+as specified in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
diff --git a/Modules/AddFileDependencies.cmake b/Modules/AddFileDependencies.cmake
index 4a4e645cd..598a52fa9 100644
--- a/Modules/AddFileDependencies.cmake
+++ b/Modules/AddFileDependencies.cmake
@@ -16,13 +16,13 @@ Adds the given ``<files>`` to the dependencies of file ``<source>``.
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}")
+ 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}")
endmacro()
diff --git a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
index afffc047f..a6e5fda38 100644
--- a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
+++ b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
@@ -26,12 +26,12 @@ endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
- return()
+ return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@")
- math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
- set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
- set(PACKAGE_VERSION_UNSUITABLE TRUE)
+ math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in
index fe5c2e5a8..43fc4d0b1 100644
--- a/Modules/BasicConfigVersion-ExactVersion.cmake.in
+++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in
@@ -41,7 +41,7 @@ endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
- return()
+ return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
diff --git a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
index d885c0f93..8c3b6a212 100644
--- a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
+++ b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
@@ -40,7 +40,7 @@ endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
- return()
+ return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
diff --git a/Modules/BasicConfigVersion-SameMinorVersion.cmake.in b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
index bf055e8d4..e2030d230 100644
--- a/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
+++ b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
@@ -44,7 +44,7 @@ endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
- return()
+ return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake
index 8c7646e4d..f94fc5cff 100644
--- a/Modules/BundleUtilities.cmake
+++ b/Modules/BundleUtilities.cmake
@@ -7,7 +7,7 @@ BundleUtilities
Functions to help assemble a standalone bundle application.
-A collection of CMake utility functions useful for dealing with .app
+A collection of CMake utility functions useful for dealing with ``.app``
bundles on the Mac and bundle-like directories on any OS.
The following functions are provided by this module:
@@ -33,7 +33,7 @@ The following functions are provided by this module:
verify_bundle_symlinks
Requires CMake 2.6 or greater because it uses function, break and
-PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
+``PARENT_SCOPE``. Also depends on ``GetPrerequisites.cmake``.
DO NOT USE THESE FUNCTIONS AT CONFIGURE TIME (from ``CMakeLists.txt``)!
Instead, invoke them from an :command:`install(CODE)` or
@@ -43,55 +43,57 @@ Instead, invoke them from an :command:`install(CODE)` or
fixup_bundle(<app> <libs> <dirs>)
-Fix up a bundle in-place and make it standalone, such that it can be
+Fix up ``<app>`` bundle in-place and make it standalone, such that it can be
drag-n-drop copied to another machine and run on that machine as long
as all of the system libraries are compatible.
-If you pass plugins to fixup_bundle as the libs parameter, you should
-install them or copy them into the bundle before calling fixup_bundle.
-The "libs" parameter is a list of libraries that must be fixed up, but
-that cannot be determined by otool output analysis. (i.e., plugins)
+If you pass plugins to ``fixup_bundle`` as the libs parameter, you should
+install them or copy them into the bundle before calling ``fixup_bundle``.
+The ``<libs>`` parameter is a list of libraries that must be fixed up, but
+that cannot be determined by ``otool`` output analysis (i.e. ``plugins``).
Gather all the keys for all the executables and libraries in a bundle,
and then, for each key, copy each prerequisite into the bundle. Then
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
+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")
+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
copy_and_fixup_bundle(<src> <dst> <libs> <dirs>)
-Makes a copy of the bundle <src> at location <dst> and then fixes up
-the new copied bundle in-place at <dst>...
+Makes a copy of the bundle ``<src>`` at location ``<dst>`` and then fixes up
+the new copied bundle in-place at ``<dst>``.
.. code-block:: cmake
verify_app(<app>)
-Verifies that an application <app> appears valid based on running
-analysis tools on it. Calls "message(FATAL_ERROR" if the application
+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")
+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
get_bundle_main_executable(<bundle> <result_var>)
The result will be the full path name of the bundle's main executable
-file or an "error:" prefixed string if it could not be determined.
+file or an ``error:`` prefixed string if it could not be determined.
.. code-block:: cmake
get_dotapp_dir(<exe> <dotapp_dir_var>)
-Returns the nearest parent dir whose name ends with ".app" given the
+Returns the nearest parent dir whose name ends with ``.app`` given the
full path to an executable. If there is no such parent dir, then
simply return the dir containing the executable.
@@ -101,26 +103,26 @@ The returned directory may or may not exist.
get_bundle_and_executable(<app> <bundle_var> <executable_var> <valid_var>)
-Takes either a ".app" directory name or the name of an executable
-nested inside a ".app" directory and returns the path to the ".app"
-directory in <bundle_var> and the path to its main executable in
-<executable_var>
+Takes either a ``.app`` directory name or the name of an executable
+nested inside a ``.app`` directory and returns the path to the ``.app``
+directory in ``<bundle_var>`` and the path to its main executable in
+``<executable_var>``.
.. code-block:: cmake
get_bundle_all_executables(<bundle> <exes_var>)
-Scans the given bundle recursively for all executable files and
-accumulates them into a variable.
+Scans ``<bundle>`` bundle recursively for all ``<exes_var>`` executable
+files and accumulates them into a variable.
.. code-block:: cmake
get_item_key(<item> <key_var>)
-Given a file (item) name, generate a key that should be unique
+Given ``<item>`` file name, generate ``<key_var>`` key that should be unique
considering the set of libraries that need copying or fixing up to
make a bundle standalone. This is essentially the file name including
-extension with "." replaced by "_"
+extension with ``.`` replaced by ``_``
This key is used as a prefix for CMake variables so that we can
associate a set of variables with a given item based on its key.
@@ -129,10 +131,10 @@ associate a set of variables with a given item based on its key.
clear_bundle_keys(<keys_var>)
-Loop over the list of keys, clearing all the variables associated with
-each key. After the loop, clear the list of keys itself.
+Loop over the ``<keys_var>`` list of keys, clearing all the variables
+associated with each key. After the loop, clear the list of keys itself.
-Caller of get_bundle_keys should call clear_bundle_keys when done with
+Caller of ``get_bundle_keys`` should call ``clear_bundle_keys`` when done with
list of keys.
.. code-block:: cmake
@@ -140,86 +142,88 @@ list of keys.
set_bundle_key_values(<keys_var> <context> <item> <exepath> <dirs>
<copyflag> [<rpaths>])
-Add a key to the list (if necessary) for the given item. If added,
-also set all the variables associated with that key.
+Add ``<keys_var>`` key to the list (if necessary) for the given item.
+If added, also set all the variables associated with that key.
.. code-block:: cmake
get_bundle_keys(<app> <libs> <dirs> <keys_var>)
-Loop over all the executable and library files within the bundle (and
-given as extra <libs>) and accumulate a list of keys representing
+Loop over all the executable and library files within ``<app>`` bundle (and
+given as extra ``<libs>``) and accumulate a list of keys representing
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.
+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")
+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
copy_resolved_item_into_bundle(<resolved_item> <resolved_embedded_item>)
-Copy a resolved item into the bundle if necessary. Copy is not
-necessary if the resolved_item is "the same as" the
-resolved_embedded_item.
+Copy a resolved item into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
.. code-block:: cmake
copy_resolved_framework_into_bundle(<resolved_item> <resolved_embedded_item>)
-Copy a resolved framework into the bundle if necessary. Copy is not
-necessary if the resolved_item is "the same as" the
-resolved_embedded_item.
+Copy a resolved framework into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
-By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want
+By default, ``BU_COPY_FULL_FRAMEWORK_CONTENTS`` is not set. If you want
full frameworks embedded in your bundles, set
-BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By
-default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework
-dylib itself plus the framework Resources directory.
+``BU_COPY_FULL_FRAMEWORK_CONTENTS`` to ``ON`` before calling fixup_bundle. By
+default, ``COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE`` copies the framework
+dylib itself plus the framework ``Resources`` directory.
.. code-block:: cmake
fixup_bundle_item(<resolved_embedded_item> <exepath> <dirs>)
-Get the direct/non-system prerequisites of the resolved embedded item.
+Get the direct/non-system prerequisites of the ``<resolved_embedded_item>``.
For each prerequisite, change the way it is referenced to the value of
-the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely
-changing to an "@executable_path" style reference.)
+the ``_EMBEDDED_ITEM`` keyed variable for that prerequisite. (Most likely
+changing to an ``@executable_path`` style reference.)
-This function requires that the resolved_embedded_item be "inside" the
-bundle already. In other words, if you pass plugins to fixup_bundle
+This function requires that the ``<resolved_embedded_item>`` be ``inside``
+the bundle already. In other words, if you pass plugins to ``fixup_bundle``
as the libs parameter, you should install them or copy them into the
-bundle before calling fixup_bundle. The "libs" parameter is a list of
+bundle before calling ``fixup_bundle``. The ``libs`` parameter is a list of
libraries that must be fixed up, but that cannot be determined by
-otool output analysis. (i.e., plugins)
+otool output analysis. (i.e., ``plugins``)
Also, change the id of the item being fixed up to its own
-_EMBEDDED_ITEM value.
+``_EMBEDDED_ITEM`` value.
Accumulate changes in a local variable and make *one* call to
-install_name_tool at the end of the function with all the changes at
+``install_name_tool`` at the end of the function with all the changes at
once.
-If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
-marked writable before install_name_tool tries to change them.
+If the ``BU_CHMOD_BUNDLE_ITEMS`` variable is set then bundle items will be
+marked writable before ``install_name_tool`` tries to change them.
.. code-block:: cmake
verify_bundle_prerequisites(<bundle> <result_var> <info_var>)
Verifies that the sum of all prerequisites of all files inside the
-bundle are contained within the bundle or are "system" libraries,
+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")
+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
verify_bundle_symlinks(<bundle> <result_var> <info_var>)
-Verifies that any symlinks found in the bundle point to other files
+Verifies that any symlinks found in the ``<bundle>`` bundle point to other files
that are already also in the bundle... Anything that points to an
external file causes this function to fail the verification.
#]=======================================================================]
diff --git a/Modules/CMakeASM_NASMInformation.cmake b/Modules/CMakeASM_NASMInformation.cmake
index 1e3c60845..cb793e7c2 100644
--- a/Modules/CMakeASM_NASMInformation.cmake
+++ b/Modules/CMakeASM_NASMInformation.cmake
@@ -28,7 +28,9 @@ if(NOT CMAKE_ASM_NASM_OBJECT_FORMAT)
endif()
endif()
-set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+if(NOT CMAKE_ASM_NASM_COMPILE_OBJECT)
+ set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+endif()
# Load the generic ASMInformation file:
set(ASM_DIALECT "_NASM")
diff --git a/Modules/CMakeAddFortranSubdirectory.cmake b/Modules/CMakeAddFortranSubdirectory.cmake
index 50b280721..2613569d1 100644
--- a/Modules/CMakeAddFortranSubdirectory.cmake
+++ b/Modules/CMakeAddFortranSubdirectory.cmake
@@ -16,7 +16,7 @@ build with the MinGW tools. It will also create imported targets for
the libraries created. This will only work if the fortran code is
built into a dll, so :variable:`BUILD_SHARED_LIBS` is turned on in
the project. In addition the :variable:`CMAKE_GNUtoMS` option is set
-to on, so that Microsoft .lib files are created. Usage is as follows:
+to on, so that Microsoft ``.lib`` files are created. Usage is as follows:
::
@@ -32,15 +32,15 @@ to on, so that Microsoft .lib files are created. Usage is as follows:
NO_EXTERNAL_INSTALL # skip installation of external project
)
-Relative paths in ARCHIVE_DIR and RUNTIME_DIR are interpreted with
+Relative paths in ``ARCHIVE_DIR`` and ``RUNTIME_DIR`` are interpreted with
respect to the build directory corresponding to the source directory
in which the function is invoked.
Limitations:
-NO_EXTERNAL_INSTALL is required for forward compatibility with a
+``NO_EXTERNAL_INSTALL`` is required for forward compatibility with a
future version that supports installation of the external project
-binaries during "make install".
+binaries during ``make install``.
#]=======================================================================]
set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
diff --git a/Modules/CMakeAddNewLanguage.txt b/Modules/CMakeAddNewLanguage.txt
index 612e1a3a5..b0be590ae 100644
--- a/Modules/CMakeAddNewLanguage.txt
+++ b/Modules/CMakeAddNewLanguage.txt
@@ -1,7 +1,7 @@
This file provides a few notes to CMake developers about how to add
support for a new language to CMake. It is also possible to place
-these files in CMAKE_MODULE_PATH within an outside project to add
-languages not supported by upstream CMake. However, this is not
+these files in :variable:`CMAKE_MODULE_PATH` within an outside project
+to add languages not supported by upstream CMake. However, this is not
a fully supported use case.
The implementation behind the scenes of project/enable_language,
@@ -17,17 +17,15 @@ changes in release notes.
CMakeDetermine(LANG)Compiler.cmake -> this should find the compiler for LANG and configure CMake(LANG)Compiler.cmake.in
CMake(LANG)Compiler.cmake.in -> used by CMakeDetermine(LANG)Compiler.cmake
- This file is used to store compiler information and is copied down into try
- compile directories so that try compiles do not need to re-determine and test the LANG
+ This file is used to store compiler information and is copied down into try
+ compile directories so that try compiles do not need to re-determine and test the LANG
CMakeTest(LANG)Compiler.cmake -> test the compiler and set:
- SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "")
+ SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "")
CMake(LANG)Information.cmake -> set up rule variables for LANG :
- CMAKE_(LANG)_CREATE_SHARED_LIBRARY
- CMAKE_(LANG)_CREATE_SHARED_MODULE
- CMAKE_(LANG)_CREATE_STATIC_LIBRARY
- CMAKE_(LANG)_COMPILE_OBJECT
- CMAKE_(LANG)_LINK_EXECUTABLE
-
-
+ CMAKE_(LANG)_CREATE_SHARED_LIBRARY
+ CMAKE_(LANG)_CREATE_SHARED_MODULE
+ CMAKE_(LANG)_CREATE_STATIC_LIBRARY
+ CMAKE_(LANG)_COMPILE_OBJECT
+ CMAKE_(LANG)_LINK_EXECUTABLE
diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in
index f473b0d1c..9b8d423a6 100644
--- a/Modules/CMakeCCompiler.cmake.in
+++ b/Modules/CMakeCCompiler.cmake.in
@@ -12,6 +12,7 @@ set(CMAKE_C11_COMPILE_FEATURES "@CMAKE_C11_COMPILE_FEATURES@")
set(CMAKE_C_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@")
set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
+set(CMAKE_C_COMPILER_FRONTEND_VARIANT "@CMAKE_C_COMPILER_FRONTEND_VARIANT@")
set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@")
@_SET_CMAKE_C_COMPILER_ARCHITECTURE_ID@
@SET_MSVC_C_ARCHITECTURE_ID@
diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in
index a1be02b5c..e7f0e7074 100644
--- a/Modules/CMakeCXXCompiler.cmake.in
+++ b/Modules/CMakeCXXCompiler.cmake.in
@@ -14,6 +14,7 @@ set(CMAKE_CXX20_COMPILE_FEATURES "@CMAKE_CXX20_COMPILE_FEATURES@")
set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
+set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "@CMAKE_CXX_COMPILER_FRONTEND_VARIANT@")
set(CMAKE_CXX_SIMULATE_VERSION "@CMAKE_CXX_SIMULATE_VERSION@")
@_SET_CMAKE_CXX_COMPILER_ARCHITECTURE_ID@
@SET_MSVC_CXX_ARCHITECTURE_ID@
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
index e60ffe019..e1ce617dc 100644
--- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -7,28 +7,29 @@
# any way between releases.
macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
- set(${_VAR}
- FAIL_REGEX "[Uu]nrecogni[sz]ed .*option" # GNU, NAG
- FAIL_REGEX "unknown .*option" # Clang
- FAIL_REGEX "optimization flag .* not supported" # Clang
- FAIL_REGEX "unknown argument ignored" # Clang (cl)
- FAIL_REGEX "ignoring unknown option" # MSVC, Intel
- FAIL_REGEX "warning D9002" # MSVC, any lang
- FAIL_REGEX "option.*not supported" # Intel
- FAIL_REGEX "invalid argument .*option" # Intel
- FAIL_REGEX "ignoring option .*argument required" # Intel
- FAIL_REGEX "ignoring option .*argument is of wrong type" # Intel
- FAIL_REGEX "[Uu]nknown option" # HP
- FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
- FAIL_REGEX "command option .* is not recognized" # XL
- FAIL_REGEX "command option .* contains an incorrect subargument" # XL
- FAIL_REGEX "Option .* is not recognized. Option will be ignored." # XL
- FAIL_REGEX "not supported in this configuration. ignored" # AIX
- FAIL_REGEX "File with unknown suffix passed to linker" # PGI
- FAIL_REGEX "[Uu]nknown switch" # PGI
- FAIL_REGEX "WARNING: unknown flag:" # Open64
- FAIL_REGEX "Incorrect command line option:" # Borland
- FAIL_REGEX "Warning: illegal option" # SunStudio 12
- FAIL_REGEX "[Ww]arning: Invalid suboption" # Fujitsu
- )
+ set(${_VAR}
+ FAIL_REGEX "[Uu]nrecogni[sz]ed .*option" # GNU, NAG
+ FAIL_REGEX "unknown .*option" # Clang
+ FAIL_REGEX "optimization flag .* not supported" # Clang
+ FAIL_REGEX "unknown argument ignored" # Clang (cl)
+ FAIL_REGEX "ignoring unknown option" # MSVC, Intel
+ FAIL_REGEX "warning D9002" # MSVC, any lang
+ FAIL_REGEX "option.*not supported" # Intel
+ FAIL_REGEX "invalid argument .*option" # Intel
+ FAIL_REGEX "ignoring option .*argument required" # Intel
+ FAIL_REGEX "ignoring option .*argument is of wrong type" # Intel
+ FAIL_REGEX "[Uu]nknown option" # HP
+ FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
+ FAIL_REGEX "command option .* is not recognized" # XL
+ FAIL_REGEX "command option .* contains an incorrect subargument" # XL
+ FAIL_REGEX "Option .* is not recognized. Option will be ignored." # XL
+ FAIL_REGEX "not supported in this configuration. ignored" # AIX
+ FAIL_REGEX "File with unknown suffix passed to linker" # PGI
+ FAIL_REGEX "[Uu]nknown switch" # PGI
+ FAIL_REGEX "WARNING: unknown flag:" # Open64
+ FAIL_REGEX "Incorrect command line option:" # Borland
+ FAIL_REGEX "Warning: illegal option" # SunStudio 12
+ FAIL_REGEX "[Ww]arning: Invalid suboption" # Fujitsu
+ FAIL_REGEX "An invalid option .* appears on the command line" # Cray
+ )
endmacro ()
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
index 6a22d2768..bb573b7dc 100644
--- a/Modules/CMakeCompilerIdDetection.cmake
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -57,6 +57,7 @@ function(compiler_id_detection outvar lang)
HP
Compaq
zOS
+ XLClang
XL
VisualAge
PGI
@@ -75,6 +76,7 @@ function(compiler_id_detection outvar lang)
SCO
ARMCC
AppleClang
+ ARMClang
Clang
GNU
MSVC
@@ -86,8 +88,6 @@ function(compiler_id_detection outvar lang)
SDCC
)
endif()
- list(APPEND ordered_compilers
- MIPSpro)
#Currently the only CUDA compilers are NVIDIA
if(lang STREQUAL CUDA)
@@ -98,6 +98,8 @@ function(compiler_id_detection outvar lang)
foreach(Id ${ordered_compilers})
string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_${Id} 0\n")
endforeach()
+ # Hard-code definitions for compilers that are no longer supported.
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_MIPSpro 0\n")
endif()
set(pp_if "#if")
diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake
index b8c8c5d35..e47f3a441 100644
--- a/Modules/CMakeDetermineASMCompiler.cmake
+++ b/Modules/CMakeDetermineASMCompiler.cmake
@@ -66,6 +66,10 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_AppleClang "--version")
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_AppleClang "(Apple LLVM version)")
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS ARMClang )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_ARMClang "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_ARMClang "armclang")
+
list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS HP )
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_HP "-V")
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_HP "HP C")
@@ -119,35 +123,40 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
CMAKE_DETERMINE_COMPILER_ID_VENDOR(ASM${ASM_DIALECT} "${userflags}")
if("x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
# primary necessary to detect architecture, so the right archiver and linker can be picked
- # eg. IAR Assembler V8.10.1.12857/W32 for ARM
+ # eg. "IAR Assembler V8.10.1.12857/W32 for ARM" or "IAR Assembler V4.11.1.4666 for Renesas RX"
# Cut out identification first, newline handling is a pain
string(REGEX MATCH "IAR Assembler[^\r\n]*" _compileid "${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT}")
if("${_compileid}" MATCHES "V([0-9]+\\.[0-9]+\\.[0-9]+)")
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION ${CMAKE_MATCH_1})
endif()
- if("${_compileid}" MATCHES "for[ ]+([A-Za-z0-9]+)")
- set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID ${CMAKE_MATCH_1})
+ string(REGEX MATCHALL "([A-Za-z0-9-]+)" _all_compileid_matches "${_compileid}")
+ if(_all_compileid_matches)
+ list(GET _all_compileid_matches "-1" CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
endif()
endif()
unset(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT)
+ unset(_all_compileid_matches)
unset(_compileid)
endif()
-
if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
if(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION)
set(_version " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION}")
else()
set(_version "")
endif()
- message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_version}")
+ if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID AND "x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
+ set(_archid " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}")
+ else()
+ set(_archid "")
+ endif()
+ message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_archid}${_version}")
+ unset(_archid)
unset(_version)
else()
message(STATUS "The ASM${ASM_DIALECT} compiler identification is unknown")
endif()
-
-
# If we have a gas/as cross compiler, they have usually some prefix, like
# e.g. powerpc-linux-gas, arm-elf-gas or i586-mingw32msvc-gas , optionally
# with a 3-component version number at the end
diff --git a/Modules/CMakeDetermineASM_MASMCompiler.cmake b/Modules/CMakeDetermineASM_MASMCompiler.cmake
index 789b0494c..80188fb25 100644
--- a/Modules/CMakeDetermineASM_MASMCompiler.cmake
+++ b/Modules/CMakeDetermineASM_MASMCompiler.cmake
@@ -8,10 +8,10 @@ set(ASM_DIALECT "_MASM")
# if we are using the 64bit cl compiler, assume we also want the 64bit assembler
if(";${CMAKE_VS_PLATFORM_NAME};${MSVC_C_ARCHITECTURE_ID};${MSVC_CXX_ARCHITECTURE_ID};"
- MATCHES ";(Win64|Itanium|x64|IA64);")
- set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml64)
+ MATCHES ";(Win64|Itanium|x64|IA64);")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml64)
else()
- set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml)
endif()
include(CMakeDetermineASMCompiler)
diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake
index d7f6f97d0..8be781a08 100644
--- a/Modules/CMakeDetermineCCompiler.cmake
+++ b/Modules/CMakeDetermineCCompiler.cmake
@@ -82,6 +82,9 @@ else()
# Try compiling K&R-compatible code (needed by Bruce C Compiler).
"-D__CLASSIC_C__"
+
+ # ARMClang need target options
+ "--target=arm-arm-none-eabi -mcpu=cortex-m3"
)
endif()
@@ -111,7 +114,6 @@ if(NOT CMAKE_C_COMPILER_ID_RUN)
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
CMAKE_DETERMINE_COMPILER_ID(C CFLAGS CMakeCCompilerId.c)
- CMAKE_DIAGNOSE_UNSUPPORTED_CLANG(C CC)
# Set old compiler and platform id variables.
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
@@ -139,8 +141,9 @@ if (CMAKE_CROSSCOMPILING AND 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]+\\.[0-9]+)?(\\.exe)?$")
+ if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(CMAKE_C_COMPILER_TARGET)
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-)
diff --git a/Modules/CMakeDetermineCSharpCompiler.cmake b/Modules/CMakeDetermineCSharpCompiler.cmake
index 5802b1511..dab941431 100644
--- a/Modules/CMakeDetermineCSharpCompiler.cmake
+++ b/Modules/CMakeDetermineCSharpCompiler.cmake
@@ -2,7 +2,7 @@
# file Copyright.txt or https://cmake.org/licensing for details.
if(NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
- message(FATAL_ERROR
+ message(FATAL_ERROR
"C# is currently only supported for Microsoft Visual Studio 2010 and later.")
endif()
diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake
index bd878b292..00ef5b9f8 100644
--- a/Modules/CMakeDetermineCXXCompiler.cmake
+++ b/Modules/CMakeDetermineCXXCompiler.cmake
@@ -77,6 +77,9 @@ else()
# IAR does not detect language automatically
"--c++"
"--ec++"
+
+ # ARMClang need target options
+ "--target=arm-arm-none-eabi -mcpu=cortex-m3"
)
endif()
@@ -106,7 +109,6 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN)
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
CMAKE_DETERMINE_COMPILER_ID(CXX CXXFLAGS CMakeCXXCompilerId.cpp)
- CMAKE_DIAGNOSE_UNSUPPORTED_CLANG(CXX CXX)
# Set old compiler and platform id variables.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -136,8 +138,9 @@ if (CMAKE_CROSSCOMPILING AND 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]+\\.[0-9]+)?(\\.exe)?$")
+ if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if(CMAKE_CXX_COMPILER_TARGET)
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_CXX_COMPILER_TARGET}-)
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 59dab6de4..6083358b3 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -28,6 +28,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
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(CMAKE_${lang}_COMPILER_ID)
@@ -45,6 +46,14 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
endif()
endforeach()
+ # Check if compiler id detection gave us the compiler tool.
+ if(CMAKE_${lang}_COMPILER_ID_TOOL)
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER_ID_TOOL}")
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER_ID_TOOL}" PARENT_SCOPE)
+ elseif(NOT CMAKE_${lang}_COMPILER)
+ set(CMAKE_${lang}_COMPILER "CMAKE_${lang}_COMPILER-NOTFOUND" PARENT_SCOPE)
+ endif()
+
# If the compiler is still unknown, try to query its vendor.
if(CMAKE_${lang}_COMPILER AND NOT CMAKE_${lang}_COMPILER_ID)
foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
@@ -75,6 +84,30 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
endif()
endif()
+ # For Swift we need to explicitly query the version.
+ if(lang STREQUAL "Swift"
+ AND CMAKE_${lang}_COMPILER
+ AND NOT CMAKE_${lang}_COMPILER_VERSION)
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ -version
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
+ "${output}\n"
+ )
+
+ if(output MATCHES [[Swift version ([0-9]+\.[0-9]+(\.[0-9]+)?)]])
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ if(NOT CMAKE_${lang}_COMPILER_ID)
+ set(CMAKE_Swift_COMPILER_ID "Apple")
+ endif()
+ endif()
+ endif()
+
if (COMPILER_QNXNTO AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
execute_process(
COMMAND "${CMAKE_${lang}_COMPILER}"
@@ -103,6 +136,31 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "")
endif()
+ set(_variant "")
+ if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang")
+ if(CMAKE_HOST_WIN32 AND "x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC")
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ # Test whether an MSVC-like command-line option works.
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -?
+ RESULT_VARIABLE _clang_result
+ OUTPUT_VARIABLE _clang_stdout
+ ERROR_VARIABLE _clang_stderr)
+ if(_clang_result EQUAL 0)
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ endif()
+ set(_variant " with ${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}-like command-line")
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "")
+ endif()
+
# Display the final identification result.
if(CMAKE_${lang}_COMPILER_ID)
if(CMAKE_${lang}_COMPILER_VERSION)
@@ -110,19 +168,20 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
else()
set(_version "")
endif()
+ if(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xIAR")
+ set(_archid " ${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}")
+ else()
+ set(_archid "")
+ endif()
message(STATUS "The ${lang} compiler identification is "
- "${CMAKE_${lang}_COMPILER_ID}${_version}")
+ "${CMAKE_${lang}_COMPILER_ID}${_archid}${_version}${_variant}")
+ unset(_archid)
+ unset(_version)
+ unset(_variant)
else()
message(STATUS "The ${lang} compiler identification is unknown")
endif()
- # Check if compiler id detection gave us the compiler tool.
- if(CMAKE_${lang}_COMPILER_ID_TOOL)
- set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER_ID_TOOL}" PARENT_SCOPE)
- elseif(NOT CMAKE_${lang}_COMPILER)
- set(CMAKE_${lang}_COMPILER "CMAKE_${lang}_COMPILER-NOTFOUND" PARENT_SCOPE)
- endif()
-
set(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
set(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}" PARENT_SCOPE)
@@ -130,6 +189,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
PARENT_SCOPE)
set(CMAKE_${lang}_XCODE_ARCHS "${CMAKE_${lang}_XCODE_ARCHS}" PARENT_SCOPE)
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "${CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_${lang}_COMPILER_VERSION}" PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_VERSION_INTERNAL "${CMAKE_${lang}_COMPILER_VERSION_INTERNAL}" PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_WRAPPER "${CMAKE_${lang}_COMPILER_WRAPPER}" PARENT_SCOPE)
@@ -182,7 +242,7 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
set(id_platform ${CMAKE_VS_PLATFORM_NAME})
set(id_lang "${lang}")
set(id_PostBuildEvent_Command "")
- if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm]$")
+ if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$")
set(id_cl_var "ClangClExecutable")
elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
set(id_cl clang.exe)
@@ -243,8 +303,8 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
else()
set(id_system "")
endif()
- if(id_system AND CMAKE_SYSTEM_VERSION)
- set(id_system_version "<ApplicationTypeRevision>${CMAKE_SYSTEM_VERSION}</ApplicationTypeRevision>")
+ if(id_system AND CMAKE_SYSTEM_VERSION MATCHES "^([0-9]+\\.[0-9]+)")
+ set(id_system_version "<ApplicationTypeRevision>${CMAKE_MATCH_1}</ApplicationTypeRevision>")
else()
set(id_system_version "")
endif()
@@ -431,10 +491,18 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
)
# Match the compiler location line printed out.
set(ghs_toolpath "${CMAKE_MAKE_PROGRAM}")
- string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
- string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+ if(CMAKE_HOST_UNIX)
+ string(REPLACE "/gbuild" "/" ghs_toolpath ${ghs_toolpath})
+ else()
+ string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
+ string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+ endif()
if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "(${ghs_toolpath}[^ ]*)")
- set(_comp "${CMAKE_MATCH_1}.exe")
+ if(CMAKE_HOST_UNIX)
+ set(_comp "${CMAKE_MATCH_1}")
+ else()
+ set(_comp "${CMAKE_MATCH_1}.exe")
+ endif()
if(EXISTS "${_comp}")
file(TO_CMAKE_PATH "${_comp}" _comp)
set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
@@ -823,38 +891,3 @@ function(CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX lang userflags)
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "" PARENT_SCOPE)
endif()
endfunction()
-
-function(CMAKE_DIAGNOSE_UNSUPPORTED_CLANG lang envvar)
- if(NOT CMAKE_HOST_WIN32 OR CMAKE_GENERATOR MATCHES "Visual Studio" OR
- NOT "${CMAKE_${lang}_COMPILER_ID};${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "Clang;MSVC")
- return()
- endif()
-
- # Test whether an MSVC-like command-line option works.
- execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -?
- RESULT_VARIABLE _clang_result
- OUTPUT_VARIABLE _clang_stdout
- ERROR_VARIABLE _clang_stderr)
- if(_clang_result EQUAL 0)
- return()
- endif()
-
- # Help the user configure the environment to use the MSVC-like Clang.
- string(CONCAT _msg
- "The Clang compiler tool\n"
- " \"${CMAKE_${lang}_COMPILER}\"\n"
- "targets the MSVC ABI but has a GNU-like command-line interface. "
- "This is not supported. "
- "Use 'clang-cl' instead, e.g. by setting '${envvar}=clang-cl' in the environment."
- )
- execute_process(COMMAND rc -help
- RESULT_VARIABLE _rc_result
- OUTPUT_VARIABLE _rc_stdout
- ERROR_VARIABLE _rc_stderr)
- if(NOT _rc_result EQUAL 0)
- string(APPEND _msg " "
- "Furthermore, use the MSVC command-line environment."
- )
- endif()
- message(FATAL_ERROR "${_msg}")
-endfunction()
diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake
index dd02d5447..2fcf7b0be 100644
--- a/Modules/CMakeDetermineSwiftCompiler.cmake
+++ b/Modules/CMakeDetermineSwiftCompiler.cmake
@@ -1,15 +1,46 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
-
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+# Local system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-Swift OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-Swift OPTIONAL)
+if(NOT CMAKE_Swift_COMPILER_NAMES)
+ set(CMAKE_Swift_COMPILER_NAMES swiftc)
+endif()
+
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
if(XCODE_VERSION VERSION_LESS 6.1)
message(FATAL_ERROR "Swift language not supported by Xcode ${XCODE_VERSION}")
endif()
set(CMAKE_Swift_COMPILER_XCODE_TYPE sourcecode.swift)
_cmake_find_compiler_path(Swift)
+elseif("${CMAKE_GENERATOR}" STREQUAL "Ninja")
+ if(CMAKE_Swift_COMPILER)
+ _cmake_find_compiler_path(Swift)
+ else()
+ set(CMAKE_Swift_COMPILER_INIT NOTFOUND)
+
+ if(NOT $ENV{SWIFTC} STREQUAL "")
+ get_filename_component(CMAKE_Swift_COMPILER_INIT $ENV{SWIFTC} PROGRAM
+ PROGRAM_ARGS CMAKE_Swift_FLAGS_ENV_INIT)
+ if(CMAKE_Swift_FLAGS_ENV_INIT)
+ set(CMAKE_Swift_COMPILER_ARG1 "${CMAKE_Swift_FLAGS_ENV_INIT}" CACHE
+ STRING "First argument to the Swift compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_Swift_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable SWIFTC\n$ENV{SWIFTC}.\n${CMAKE_Swift_COMPILER_INIT}")
+ endif()
+ endif()
+
+ if(NOT CMAKE_Swift_COMPILER_INIT)
+ set(CMAKE_Swift_COMPILER_LIST swiftc ${_CMAKE_TOOLCHAIN_PREFIX}swiftc)
+ endif()
+
+ _cmake_find_compiler(Swift)
+ endif()
+ mark_as_advanced(CMAKE_Swift_COMPILER)
else()
message(FATAL_ERROR "Swift language not supported by \"${CMAKE_GENERATOR}\" generator")
endif()
@@ -18,11 +49,13 @@ endif()
if(NOT CMAKE_Swift_COMPILER_ID_RUN)
set(CMAKE_Swift_COMPILER_ID_RUN 1)
- list(APPEND CMAKE_Swift_COMPILER_ID_MATCH_VENDORS Apple)
- set(CMAKE_Swift_COMPILER_ID_MATCH_VENDOR_REGEX_Apple "com.apple.xcode.tools.swift.compiler")
+ if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
+ list(APPEND CMAKE_Swift_COMPILER_ID_MATCH_VENDORS Apple)
+ set(CMAKE_Swift_COMPILER_ID_MATCH_VENDOR_REGEX_Apple "com.apple.xcode.tools.swift.compiler")
- set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_REGEX "\nCompileSwiftSources[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]* -c[^\r\n]*CompilerIdSwift/CompilerId/main.swift")
- set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_INDEX 2)
+ set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_REGEX "\nCompileSwiftSources[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]* -c[^\r\n]*CompilerIdSwift/CompilerId/main.swift")
+ set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_INDEX 2)
+ endif()
# Try to identify the compiler.
set(CMAKE_Swift_COMPILER_ID)
@@ -40,6 +73,6 @@ unset(_CMAKE_PROCESSING_LANGUAGE)
# configure variables set in this file for fast reload later on
configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in
- ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake
- @ONLY
- )
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake @ONLY)
+
+set(CMAKE_Swift_COMPILER_ENV_VAR "SWIFTC")
diff --git a/Modules/CMakeDetermineVSServicePack.cmake b/Modules/CMakeDetermineVSServicePack.cmake
index a3c4d9cf1..53868d21a 100644
--- a/Modules/CMakeDetermineVSServicePack.cmake
+++ b/Modules/CMakeDetermineVSServicePack.cmake
@@ -44,32 +44,32 @@ endif()
# [INTERNAL]
# Please do not call this function directly
function(_DetermineVSServicePackFromCompiler _OUT_VAR _cl_version)
- if (${_cl_version} VERSION_EQUAL "14.00.50727.42")
- set(_version "vc80")
- elseif(${_cl_version} VERSION_EQUAL "14.00.50727.762")
- set(_version "vc80sp1")
- elseif(${_cl_version} VERSION_EQUAL "15.00.21022.08")
- set(_version "vc90")
- elseif(${_cl_version} VERSION_EQUAL "15.00.30729.01")
- set(_version "vc90sp1")
- elseif(${_cl_version} VERSION_EQUAL "16.00.30319.01")
- set(_version "vc100")
- elseif(${_cl_version} VERSION_EQUAL "16.00.40219.01")
- set(_version "vc100sp1")
- elseif(${_cl_version} VERSION_EQUAL "17.00.50727.1")
- set(_version "vc110")
- elseif(${_cl_version} VERSION_EQUAL "17.00.51106.1")
- set(_version "vc110sp1")
- elseif(${_cl_version} VERSION_EQUAL "17.00.60315.1")
- set(_version "vc110sp2")
- elseif(${_cl_version} VERSION_EQUAL "17.00.60610.1")
- set(_version "vc110sp3")
- elseif(${_cl_version} VERSION_EQUAL "17.00.61030")
- set(_version "vc110sp4")
- else()
- set(_version "")
- endif()
- set(${_OUT_VAR} ${_version} PARENT_SCOPE)
+ if (${_cl_version} VERSION_EQUAL "14.00.50727.42")
+ set(_version "vc80")
+ elseif(${_cl_version} VERSION_EQUAL "14.00.50727.762")
+ set(_version "vc80sp1")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.21022.08")
+ set(_version "vc90")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.30729.01")
+ set(_version "vc90sp1")
+ elseif(${_cl_version} VERSION_EQUAL "16.00.30319.01")
+ set(_version "vc100")
+ elseif(${_cl_version} VERSION_EQUAL "16.00.40219.01")
+ set(_version "vc100sp1")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.50727.1")
+ set(_version "vc110")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.51106.1")
+ set(_version "vc110sp1")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.60315.1")
+ set(_version "vc110sp2")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.60610.1")
+ set(_version "vc110sp3")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.61030")
+ set(_version "vc110sp4")
+ else()
+ set(_version "")
+ endif()
+ set(${_OUT_VAR} ${_version} PARENT_SCOPE)
endfunction()
diff --git a/Modules/CMakeExpandImportedTargets.cmake b/Modules/CMakeExpandImportedTargets.cmake
index ae26cc26e..b8f471c10 100644
--- a/Modules/CMakeExpandImportedTargets.cmake
+++ b/Modules/CMakeExpandImportedTargets.cmake
@@ -42,108 +42,107 @@ ${CMAKE_CONFIGURATION_TYPES} if set, otherwise ${CMAKE_BUILD_TYPE}.
function(CMAKE_EXPAND_IMPORTED_TARGETS _RESULT )
- set(options )
- set(oneValueArgs CONFIGURATION )
- set(multiValueArgs LIBRARIES )
-
- cmake_parse_arguments(CEIT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
- if(CEIT_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to CMAKE_EXPAND_IMPORTED_TARGETS(): \"${CEIT_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if(NOT CEIT_CONFIGURATION)
- # Would be better to test GENERATOR_IS_MULTI_CONFIG global property,
- # but the documented behavior specifically says we check
- # CMAKE_CONFIGURATION_TYPES and fall back to CMAKE_BUILD_TYPE if no
- # config types are defined.
- if(CMAKE_CONFIGURATION_TYPES)
- list(GET CMAKE_CONFIGURATION_TYPES 0 CEIT_CONFIGURATION)
- else()
- set(CEIT_CONFIGURATION ${CMAKE_BUILD_TYPE})
- endif()
- endif()
-
- # handle imported library targets
-
- set(_CCSR_REQ_LIBS ${CEIT_LIBRARIES})
-
- set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
- set(_CCSR_LOOP_COUNTER 0)
- while(_CHECK_FOR_IMPORTED_TARGETS)
- math(EXPR _CCSR_LOOP_COUNTER "${_CCSR_LOOP_COUNTER} + 1 ")
- set(_CCSR_NEW_REQ_LIBS )
- set(_CHECK_FOR_IMPORTED_TARGETS FALSE)
- foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
- if(TARGET "${_CURRENT_LIB}")
- get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
- else()
- set(_importedConfigs "")
- endif()
- if (_importedConfigs)
-# message(STATUS "Detected imported target ${_CURRENT_LIB}")
- # Ok, so this is an imported target.
- # First we get the imported configurations.
- # Then we get the location of the actual library on disk of the first configuration.
- # then we'll get its link interface libraries property,
- # iterate through it and replace all imported targets we find there
- # with there actual location.
-
- # guard against infinite loop: abort after 100 iterations ( 100 is arbitrary chosen)
- if ("${_CCSR_LOOP_COUNTER}" LESS 100)
- set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
-# else ()
-# message(STATUS "********* aborting loop, counter : ${_CCSR_LOOP_COUNTER}")
- endif ()
-
- # if one of the imported configurations equals ${CMAKE_TRY_COMPILE_CONFIGURATION},
- # use it, otherwise simply use the first one:
- list(FIND _importedConfigs "${CEIT_CONFIGURATION}" _configIndexToUse)
- if("${_configIndexToUse}" EQUAL -1)
- set(_configIndexToUse 0)
- endif()
- list(GET _importedConfigs ${_configIndexToUse} _importedConfigToUse)
-
- get_target_property(_importedLocation "${_CURRENT_LIB}" IMPORTED_LOCATION_${_importedConfigToUse})
- get_target_property(_linkInterfaceLibs "${_CURRENT_LIB}" IMPORTED_LINK_INTERFACE_LIBRARIES_${_importedConfigToUse} )
-
- list(APPEND _CCSR_NEW_REQ_LIBS "${_importedLocation}")
-# message(STATUS "Appending lib ${_CURRENT_LIB} as ${_importedLocation}")
- if(_linkInterfaceLibs)
- foreach(_currentLinkInterfaceLib ${_linkInterfaceLibs})
-# message(STATUS "Appending link interface lib ${_currentLinkInterfaceLib}")
- if(_currentLinkInterfaceLib)
- list(APPEND _CCSR_NEW_REQ_LIBS "${_currentLinkInterfaceLib}" )
- endif()
- endforeach()
- endif()
- else()
- # "Normal" libraries are just used as they are.
- list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
-# message(STATUS "Appending lib directly: ${_CURRENT_LIB}")
- endif()
- endforeach()
-
- set(_CCSR_REQ_LIBS ${_CCSR_NEW_REQ_LIBS} )
- endwhile()
-
- # Finally we iterate once more over all libraries. This loop only removes
- # all remaining imported target names (there shouldn't be any left anyway).
- set(_CCSR_NEW_REQ_LIBS )
- foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
+ set(options )
+ set(oneValueArgs CONFIGURATION )
+ set(multiValueArgs LIBRARIES )
+
+ cmake_parse_arguments(CEIT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CEIT_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to CMAKE_EXPAND_IMPORTED_TARGETS(): \"${CEIT_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT CEIT_CONFIGURATION)
+ # Would be better to test GENERATOR_IS_MULTI_CONFIG global property,
+ # but the documented behavior specifically says we check
+ # CMAKE_CONFIGURATION_TYPES and fall back to CMAKE_BUILD_TYPE if no
+ # config types are defined.
+ if(CMAKE_CONFIGURATION_TYPES)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 CEIT_CONFIGURATION)
+ else()
+ set(CEIT_CONFIGURATION ${CMAKE_BUILD_TYPE})
+ endif()
+ endif()
+
+ # handle imported library targets
+
+ set(_CCSR_REQ_LIBS ${CEIT_LIBRARIES})
+
+ set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
+ set(_CCSR_LOOP_COUNTER 0)
+ while(_CHECK_FOR_IMPORTED_TARGETS)
+ math(EXPR _CCSR_LOOP_COUNTER "${_CCSR_LOOP_COUNTER} + 1 ")
+ set(_CCSR_NEW_REQ_LIBS )
+ set(_CHECK_FOR_IMPORTED_TARGETS FALSE)
+ foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
if(TARGET "${_CURRENT_LIB}")
get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
else()
set(_importedConfigs "")
endif()
- if (NOT _importedConfigs)
- list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
-# message(STATUS "final: appending ${_CURRENT_LIB}")
- else ()
-# message(STATUS "final: skipping ${_CURRENT_LIB}")
- endif ()
- endforeach()
-# message(STATUS "setting -${_RESULT}- to -${_CCSR_NEW_REQ_LIBS}-")
- set(${_RESULT} "${_CCSR_NEW_REQ_LIBS}" PARENT_SCOPE)
+ if (_importedConfigs)
+ # message(STATUS "Detected imported target ${_CURRENT_LIB}")
+ # Ok, so this is an imported target.
+ # First we get the imported configurations.
+ # Then we get the location of the actual library on disk of the first configuration.
+ # then we'll get its link interface libraries property,
+ # iterate through it and replace all imported targets we find there
+ # with there actual location.
+
+ # guard against infinite loop: abort after 100 iterations ( 100 is arbitrary chosen)
+ if ("${_CCSR_LOOP_COUNTER}" LESS 100)
+ set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
+# else ()
+# message(STATUS "********* aborting loop, counter : ${_CCSR_LOOP_COUNTER}")
+ endif ()
+
+ # if one of the imported configurations equals ${CMAKE_TRY_COMPILE_CONFIGURATION},
+ # use it, otherwise simply use the first one:
+ list(FIND _importedConfigs "${CEIT_CONFIGURATION}" _configIndexToUse)
+ if("${_configIndexToUse}" EQUAL -1)
+ set(_configIndexToUse 0)
+ endif()
+ list(GET _importedConfigs ${_configIndexToUse} _importedConfigToUse)
+
+ get_target_property(_importedLocation "${_CURRENT_LIB}" IMPORTED_LOCATION_${_importedConfigToUse})
+ get_target_property(_linkInterfaceLibs "${_CURRENT_LIB}" IMPORTED_LINK_INTERFACE_LIBRARIES_${_importedConfigToUse} )
+
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_importedLocation}")
+# message(STATUS "Appending lib ${_CURRENT_LIB} as ${_importedLocation}")
+ if(_linkInterfaceLibs)
+ foreach(_currentLinkInterfaceLib ${_linkInterfaceLibs})
+# message(STATUS "Appending link interface lib ${_currentLinkInterfaceLib}")
+ if(_currentLinkInterfaceLib)
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_currentLinkInterfaceLib}" )
+ endif()
+ endforeach()
+ endif()
+ else()
+ # "Normal" libraries are just used as they are.
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
+# message(STATUS "Appending lib directly: ${_CURRENT_LIB}")
+ endif()
+ endforeach()
+ set(_CCSR_REQ_LIBS ${_CCSR_NEW_REQ_LIBS} )
+ endwhile()
+
+ # Finally we iterate once more over all libraries. This loop only removes
+ # all remaining imported target names (there shouldn't be any left anyway).
+ set(_CCSR_NEW_REQ_LIBS )
+ foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
+ if(TARGET "${_CURRENT_LIB}")
+ get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ else()
+ set(_importedConfigs "")
+ endif()
+ if (NOT _importedConfigs)
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
+# message(STATUS "final: appending ${_CURRENT_LIB}")
+# else ()
+# message(STATUS "final: skipping ${_CURRENT_LIB}")
+ endif ()
+ endforeach()
+# message(STATUS "setting -${_RESULT}- to -${_CCSR_NEW_REQ_LIBS}-")
+ set(${_RESULT} "${_CCSR_NEW_REQ_LIBS}" PARENT_SCOPE)
endfunction()
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index 35f75c938..0e8411640 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -60,7 +60,9 @@ __resolve_tool_path(CMAKE_MT "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Manifes
set(_CMAKE_TOOL_VARS "")
# if it's the MS C/CXX compiler, search for link
-if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC"
+if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
+ ("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"
+ OR NOT "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang"))
OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC"
OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI")
OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xNVIDIA")
@@ -80,17 +82,26 @@ else()
if(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
endif()
- find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+ if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
+ set(LLVM_OBJDUMP "llvm-objdump")
+ set(LLVM_LLD "ld.lld")
+ set(LLVM_RANLIB "llvm-ranlib")
+ set(LLVM_AR "llvm-ar")
+ endif()
+
+ find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} ${LLVM_AR} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+
+ find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib ${LLVM_RANLIB} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
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} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+ find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld ${LLVM_LLD} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+ find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump ${LLVM_OBJDUMP} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
find_program(CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
list(APPEND _CMAKE_TOOL_VARS CMAKE_AR CMAKE_RANLIB CMAKE_STRIP CMAKE_LINKER CMAKE_NM CMAKE_OBJDUMP CMAKE_OBJCOPY)
diff --git a/Modules/CMakeFindCodeBlocks.cmake b/Modules/CMakeFindCodeBlocks.cmake
index 13bceb1a8..bf27ec111 100644
--- a/Modules/CMakeFindCodeBlocks.cmake
+++ b/Modules/CMakeFindCodeBlocks.cmake
@@ -8,7 +8,7 @@
find_program(CMAKE_CODEBLOCKS_EXECUTABLE NAMES codeblocks DOC "The CodeBlocks executable")
if(CMAKE_CODEBLOCKS_EXECUTABLE)
- set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_CODEBLOCKS_EXECUTABLE} <PROJECT_FILE>" )
+ set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_CODEBLOCKS_EXECUTABLE} <PROJECT_FILE>" )
endif()
# Determine builtin macros and include dirs:
diff --git a/Modules/CMakeFindDependencyMacro.cmake b/Modules/CMakeFindDependencyMacro.cmake
index de1a3329a..bcdfbebe3 100644
--- a/Modules/CMakeFindDependencyMacro.cmake
+++ b/Modules/CMakeFindDependencyMacro.cmake
@@ -31,36 +31,33 @@ CMakeFindDependencyMacro
#]=======================================================================]
macro(find_dependency dep)
- if (NOT ${dep}_FOUND)
- set(cmake_fd_quiet_arg)
- if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
- set(cmake_fd_quiet_arg QUIET)
- endif()
- set(cmake_fd_required_arg)
- if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
- set(cmake_fd_required_arg REQUIRED)
- endif()
+ set(cmake_fd_quiet_arg)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ set(cmake_fd_quiet_arg QUIET)
+ endif()
+ set(cmake_fd_required_arg)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+ set(cmake_fd_required_arg REQUIRED)
+ endif()
- get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
- _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
- )
+ get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
+ _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
+ )
- find_package(${dep} ${ARGN}
- ${cmake_fd_quiet_arg}
- ${cmake_fd_required_arg}
- )
+ find_package(${dep} ${ARGN}
+ ${cmake_fd_quiet_arg}
+ ${cmake_fd_required_arg}
+ )
- if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
- set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
- endif()
+ if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
+ set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
+ endif()
- if (NOT ${dep}_FOUND)
- set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
- set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
- return()
- endif()
- set(cmake_fd_required_arg)
- set(cmake_fd_quiet_arg)
- set(cmake_fd_exact_arg)
+ if (NOT ${dep}_FOUND)
+ set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
+ set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+ return()
endif()
+ set(cmake_fd_required_arg)
+ set(cmake_fd_quiet_arg)
endmacro()
diff --git a/Modules/CMakeFindSublimeText2.cmake b/Modules/CMakeFindSublimeText2.cmake
index 022d0109e..7f67bf03d 100644
--- a/Modules/CMakeFindSublimeText2.cmake
+++ b/Modules/CMakeFindSublimeText2.cmake
@@ -19,5 +19,5 @@ find_program(CMAKE_SUBLIMETEXT_EXECUTABLE
DOC "The Sublime Text executable")
if(CMAKE_SUBLIMETEXT_EXECUTABLE)
- set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_SUBLIMETEXT_EXECUTABLE} --project <PROJECT_FILE>" )
+ set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_SUBLIMETEXT_EXECUTABLE} --project <PROJECT_FILE>" )
endif()
diff --git a/Modules/CMakeForceCompiler.cmake b/Modules/CMakeForceCompiler.cmake
index 7ac09dcaa..704880631 100644
--- a/Modules/CMakeForceCompiler.cmake
+++ b/Modules/CMakeForceCompiler.cmake
@@ -25,38 +25,41 @@ toolchain file instead.
-------------------------------------------------------------------------
-Macro CMAKE_FORCE_C_COMPILER has the following signature:
+Macro ``CMAKE_FORCE_C_COMPILER`` has the following signature:
::
CMAKE_FORCE_C_COMPILER(<compiler> <compiler-id>)
-It sets CMAKE_C_COMPILER to the given compiler and the cmake internal
-variable CMAKE_C_COMPILER_ID to the given compiler-id. It also
-bypasses the check for working compiler and basic compiler information
-tests.
+It sets :variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_C_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
-Macro CMAKE_FORCE_CXX_COMPILER has the following signature:
+Macro ``CMAKE_FORCE_CXX_COMPILER`` has the following signature:
::
CMAKE_FORCE_CXX_COMPILER(<compiler> <compiler-id>)
-It sets CMAKE_CXX_COMPILER to the given compiler and the cmake
-internal variable CMAKE_CXX_COMPILER_ID to the given compiler-id. It
-also bypasses the check for working compiler and basic compiler
-information tests.
+It sets :variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
-Macro CMAKE_FORCE_Fortran_COMPILER has the following signature:
+Macro ``CMAKE_FORCE_Fortran_COMPILER`` has the following signature:
::
CMAKE_FORCE_Fortran_COMPILER(<compiler> <compiler-id>)
-It sets CMAKE_Fortran_COMPILER to the given compiler and the cmake
-internal variable CMAKE_Fortran_COMPILER_ID to the given compiler-id.
-It also bypasses the check for working compiler and basic compiler
-information tests.
+It sets :variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
So a simple toolchain file could look like this:
diff --git a/Modules/CMakeFortranCompilerId.F.in b/Modules/CMakeFortranCompilerId.F.in
index 59956944b..30f8d4c45 100644
--- a/Modules/CMakeFortranCompilerId.F.in
+++ b/Modules/CMakeFortranCompilerId.F.in
@@ -96,13 +96,6 @@
# if defined(__FLANG_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__FLANG_PATCHLEVEL__)
# endif
-#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION)
- PRINT *, 'INFO:compiler[MIPSpro]'
-# if 0
-! This compiler is either not known or is too old to define an
-! identification macro. Try to identify the platform and guess that
-! it is the native compiler.
-# endif
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
PRINT *, 'INFO:compiler[VisualAge]'
#elif defined(__hpux) || defined(__hpux__)
diff --git a/Modules/CMakeJavaInformation.cmake b/Modules/CMakeJavaInformation.cmake
index 11568a810..989afc11b 100644
--- a/Modules/CMakeJavaInformation.cmake
+++ b/Modules/CMakeJavaInformation.cmake
@@ -16,8 +16,8 @@ endif()
if(CMAKE_USER_MAKE_RULES_OVERRIDE_Java)
# Save the full path of the file so try_compile can use it.
- include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Java} RESULT_VARIABLE _override)
- set(CMAKE_USER_MAKE_RULES_OVERRIDE_Java "${_override}")
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Java} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_Java "${_override}")
endif()
# this is a place holder if java needed flags for javac they would go here.
diff --git a/Modules/CMakeNinjaFindMake.cmake b/Modules/CMakeNinjaFindMake.cmake
index 6a0c47eec..702af1338 100644
--- a/Modules/CMakeNinjaFindMake.cmake
+++ b/Modules/CMakeNinjaFindMake.cmake
@@ -3,6 +3,6 @@
find_program(CMAKE_MAKE_PROGRAM
- NAMES ninja-build ninja
+ NAMES ninja-build ninja samu
DOC "Program used to build from build.ninja files.")
mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeParseImplicitIncludeInfo.cmake b/Modules/CMakeParseImplicitIncludeInfo.cmake
index f044b106a..91d03cdc9 100644
--- a/Modules/CMakeParseImplicitIncludeInfo.cmake
+++ b/Modules/CMakeParseImplicitIncludeInfo.cmake
@@ -92,13 +92,15 @@ function(cmake_parse_implicit_include_line line lang id_var log_var state_var)
endif()
# XL compiler
- if("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XL" AND "${line}" MATCHES "^/"
+ if(("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XL"
+ OR "${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XLClang")
+ AND "${line}" MATCHES "^/"
AND ( ("${lang}" STREQUAL "Fortran" AND
"${line}" MATCHES "/xl[fF]entry " AND
"${line}" MATCHES "OSVAR\\([^ ]+\\)")
OR
( ("${lang}" STREQUAL "C" OR "${lang}" STREQUAL "CXX") AND
- "${line}" MATCHES "/xl[cC]entry " AND
+ "${line}" MATCHES "/xl[cC]2?entry " AND
"${line}" MATCHES " -qosvar=")
) )
# -qnostdinc cancels other stdinc flags, even if present
diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in
index 3cb7f2474..542a6fe3c 100644
--- a/Modules/CMakePlatformId.h.in
+++ b/Modules/CMakePlatformId.h.in
@@ -156,9 +156,24 @@
# if defined(__ICCARM__)
# define ARCHITECTURE_ID "ARM"
+# elif defined(__ICCRX__)
+# define ARCHITECTURE_ID "RX"
+
+# elif defined(__ICCRH850__)
+# define ARCHITECTURE_ID "RH850"
+
+# elif defined(__ICCRL78__)
+# define ARCHITECTURE_ID "RL78"
+
+# elif defined(__ICCRISCV__)
+# define ARCHITECTURE_ID "RISCV"
+
# elif defined(__ICCAVR__)
# define ARCHITECTURE_ID "AVR"
+# elif defined(__ICC430__)
+# define ARCHITECTURE_ID "MSP430"
+
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
diff --git a/Modules/CMakePrintHelpers.cmake b/Modules/CMakePrintHelpers.cmake
index 1af0bb730..aa40b59ca 100644
--- a/Modules/CMakePrintHelpers.cmake
+++ b/Modules/CMakePrintHelpers.cmake
@@ -42,14 +42,14 @@ Gives::
#]=======================================================================]
function(cmake_print_variables)
- set(msg "")
- foreach(var ${ARGN})
- if(msg)
- string(APPEND msg " ; ")
- endif()
- string(APPEND msg "${var}=\"${${var}}\"")
- endforeach()
- message(STATUS "${msg}")
+ set(msg "")
+ foreach(var ${ARGN})
+ if(msg)
+ string(APPEND msg " ; ")
+ endif()
+ string(APPEND msg "${var}=\"${${var}}\"")
+ endforeach()
+ message(STATUS "${msg}")
endfunction()
diff --git a/Modules/CMakePushCheckState.cmake b/Modules/CMakePushCheckState.cmake
index f6bfc120e..3e519ee51 100644
--- a/Modules/CMakePushCheckState.cmake
+++ b/Modules/CMakePushCheckState.cmake
@@ -40,52 +40,52 @@ Usage:
macro(CMAKE_RESET_CHECK_STATE)
- set(CMAKE_EXTRA_INCLUDE_FILES)
- set(CMAKE_REQUIRED_INCLUDES)
- set(CMAKE_REQUIRED_DEFINITIONS)
- set(CMAKE_REQUIRED_LINK_OPTIONS)
- set(CMAKE_REQUIRED_LIBRARIES)
- set(CMAKE_REQUIRED_FLAGS)
- set(CMAKE_REQUIRED_QUIET)
+ set(CMAKE_EXTRA_INCLUDE_FILES)
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_DEFINITIONS)
+ set(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ set(CMAKE_REQUIRED_FLAGS)
+ set(CMAKE_REQUIRED_QUIET)
endmacro()
macro(CMAKE_PUSH_CHECK_STATE)
- if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
- set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
- endif()
+ if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
+ set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
+ endif()
- math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
- set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES})
- set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
- set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
- set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_OPTIONS})
- set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
- set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
- set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET})
+ set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES})
+ set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
+ set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
+ set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_OPTIONS})
+ set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
+ set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
+ set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET})
- if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET")
- cmake_reset_check_state()
- endif()
+ if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET")
+ cmake_reset_check_state()
+ endif()
endmacro()
macro(CMAKE_POP_CHECK_STATE)
# don't pop more than we pushed
- if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
-
- set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_LINK_OPTIONS ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
- set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
-
- math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
- endif()
+ if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
+
+ set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_LINK_OPTIONS ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
+ endif()
endmacro()
diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake
index 1227fdf26..7bf656775 100644
--- a/Modules/CMakeRCInformation.cmake
+++ b/Modules/CMakeRCInformation.cmake
@@ -32,7 +32,7 @@ set(CMAKE_INCLUDE_FLAG_RC "-I")
# compile a Resource file into an object file
if(NOT CMAKE_RC_COMPILE_OBJECT)
set(CMAKE_RC_COMPILE_OBJECT
- "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /fo<OBJECT> <SOURCE>")
+ "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /fo <OBJECT> <SOURCE>")
endif()
# set this variable so we can avoid loading this more than once.
diff --git a/Modules/CMakeSwiftCompiler.cmake.in b/Modules/CMakeSwiftCompiler.cmake.in
index 45f0a3105..7c8d1c19a 100644
--- a/Modules/CMakeSwiftCompiler.cmake.in
+++ b/Modules/CMakeSwiftCompiler.cmake.in
@@ -1,5 +1,14 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
set(CMAKE_Swift_COMPILER "@CMAKE_Swift_COMPILER@")
set(CMAKE_Swift_COMPILER_ID "@CMAKE_Swift_COMPILER_ID@")
+set(CMAKE_Swift_COMPILER_VERSION "@CMAKE_Swift_COMPILER_VERSION@")
+
+set(CMAKE_Swift_COMPILER_LOADED 1)
+set(CMAKE_Swift_COMPILER_WORKS "@CMAKE_Swift_COMPILER_WORKS@")
+
+set(CMAKE_Swift_COMPILER_ENV_VAR "SWIFTC")
set(CMAKE_Swift_COMPILER_ID_RUN 1)
set(CMAKE_Swift_SOURCE_FILE_EXTENSIONS swift)
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 07ba6d077..21f18d400 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -1,32 +1,75 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
-
-set(CMAKE_Swift_OUTPUT_EXTENSION .o)
-set(CMAKE_INCLUDE_FLAG_Swift "-I")
+if(UNIX)
+ set(CMAKE_Swift_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_Swift_OUTPUT_EXTENSION .obj)
+endif()
# Load compiler-specific information.
if(CMAKE_Swift_COMPILER_ID)
include(Compiler/${CMAKE_Swift_COMPILER_ID}-Swift OPTIONAL)
-endif()
-# load the system- and compiler specific files
-if(CMAKE_Swift_COMPILER_ID)
- # load a hardware specific file, mostly useful for embedded compilers
if(CMAKE_SYSTEM_PROCESSOR)
include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Swift_COMPILER_ID}-Swift-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
endif()
include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Swift_COMPILER_ID}-Swift OPTIONAL)
endif()
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
- set(CMAKE_SHARED_MODULE_Swift_FLAGS ${CMAKE_SHARED_LIBRARY_Swift_FLAGS})
- set(CMAKE_SHARED_MODULE_CREATE_Swift_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_Swift_FLAGS})
+set(CMAKE_INCLUDE_FLAG_Swift "-I ")
+
+set(CMAKE_Swift_COMPILE_OPTIONS_TARGET "-target ")
+set(CMAKE_Swift_COMPILER_ARG1 -frontend)
+set(CMAKE_Swift_DEFINE_FLAG -D)
+set(CMAKE_Swift_FRAMEWORK_SEARCH_FLAG "-F ")
+set(CMAKE_Swift_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+set(CMAKE_Swift_RESPONSE_FILE_LINK_FLAG @)
+
+set(CMAKE_Swift_LINKER_PREFERENCE 50)
+set(CMAKE_Swift_LINKER_PREFERENCE_PROPAGATES 1)
+
+# NOTE(compnerd) use the short form for convenience and ease of search. They
+# are treated equivalent to their long form names as well as custom Swift
+# specific names.
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -libc MT)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -libc MD)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -libc MTd)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -libc MDd)
+
+set(CMAKE_Swift_FLAGS_DEBUG_INIT "-g")
+set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
+set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+
+# NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step
+if(NOT CMAKE_Swift_COMPILE_OBJECT)
+ set(CMAKE_Swift_COMPILE_OBJECT ":")
+endif()
+
+if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY)
+ if(CMAKE_Swift_COMPILER_TARGET)
+ set(CMAKE_Swift_CREATE_SHARED_LIBRARY "${CMAKE_Swift_COMPILER} -target <CMAKE_Swift_COMPILER_TARGET> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ else()
+ set(CMAKE_Swift_CREATE_SHARED_LIBRARY "${CMAKE_Swift_COMPILER} -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ endif()
+endif()
+
+if(NOT CMAKE_Swift_CREATE_SHARED_MODULE)
+ set(CMAKE_Swift_CREATE_SHARED_MODULE ${CMAKE_Swift_CREATE_SHARED_LIBRARY})
endif()
-include(CMakeCommonLanguageInclude)
+if(NOT CMAKE_Swift_LINK_EXECUTABLE)
+ if(CMAKE_Swift_COMPILER_TARGET)
+ set(CMAKE_Swift_LINK_EXECUTABLE "${CMAKE_Swift_COMPILER} -target <CMAKE_Swift_COMPILER_TARGET> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -emit-executable -o <TARGET> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ else()
+ set(CMAKE_Swift_LINK_EXECUTABLE "${CMAKE_Swift_COMPILER} -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -emit-executable -o <TARGET> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ endif()
+endif()
+
+if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY)
+ set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>")
+ set(CMAKE_Swift_ARCHIVE_FINISH "")
+endif()
set(CMAKE_Swift_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeSystemSpecificInformation.cmake b/Modules/CMakeSystemSpecificInformation.cmake
index 66f172277..c6a88144f 100644
--- a/Modules/CMakeSystemSpecificInformation.cmake
+++ b/Modules/CMakeSystemSpecificInformation.cmake
@@ -34,7 +34,7 @@ if(NOT _INCLUDED_SYSTEM_INFO_FILE)
${CMAKE_BINARY_DIR}/CopyOfCMakeCache.txt COPYONLY)
message("Your CMakeCache.txt file was copied to CopyOfCMakeCache.txt. "
"Please send that file to cmake@www.cmake.org.")
- endif()
+ endif()
endif()
# optionally include a file which can do extra-generator specific things, e.g.
diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake
index 858c1be79..841aee643 100644
--- a/Modules/CMakeTestSwiftCompiler.cmake
+++ b/Modules/CMakeTestSwiftCompiler.cmake
@@ -1,7 +1,6 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
-
if(CMAKE_Swift_COMPILER_FORCED)
# The compiler configuration was forced by the user.
# Assume the user has configured all compiler information.
@@ -23,7 +22,6 @@ unset(CMAKE_Swift_COMPILER_WORKS CACHE)
if(NOT CMAKE_Swift_COMPILER_WORKS)
PrintTestCompilerStatus("Swift" "")
file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.swift
- "import Foundation\n"
"print(\"CMake\")\n")
try_compile(CMAKE_Swift_COMPILER_WORKS ${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.swift
@@ -51,6 +49,11 @@ else()
"Determining if the Swift compiler works passed with "
"the following output:\n${__CMAKE_Swift_COMPILER_OUTPUT}\n\n")
endif()
+
+ # Re-configure to save learned information.
+ configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake @ONLY)
+ include(${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake)
endif()
unset(__CMAKE_Swift_COMPILER_OUTPUT)
diff --git a/Modules/CTestCoverageCollectGCOV.cmake b/Modules/CTestCoverageCollectGCOV.cmake
index 2258271cc..655827a73 100644
--- a/Modules/CTestCoverageCollectGCOV.cmake
+++ b/Modules/CTestCoverageCollectGCOV.cmake
@@ -52,7 +52,7 @@ After generating this tar file, it can be sent to CDash for display with the
``GCOV_OPTIONS <options>...``
Specify options to be passed to gcov. The ``gcov`` command
is run as ``gcov <options>... -o <gcov-dir> <file>.gcda``.
- If not specified, the default option is just ``-b``.
+ If not specified, the default option is just ``-b -x``.
``GLOB``
Recursively search for .gcda files in build_dir rather than
@@ -95,7 +95,7 @@ function(ctest_coverage_collect_gcov)
set(gcda_files)
set(label_files)
if (GCOV_GLOB)
- file(GLOB_RECURSE gfiles RELATIVE ${binary_dir} "${binary_dir}/*.gcda")
+ file(GLOB_RECURSE gfiles "${binary_dir}/*.gcda")
list(LENGTH gfiles len)
# if we have gcda files then also grab the labels file for that target
if(${len} GREATER 0)
@@ -109,7 +109,7 @@ function(ctest_coverage_collect_gcov)
file(STRINGS "${binary_dir}/CMakeFiles/TargetDirectories.txt" target_dirs
ENCODING UTF-8)
foreach(target_dir ${target_dirs})
- file(GLOB_RECURSE gfiles RELATIVE ${binary_dir} "${target_dir}/*.gcda")
+ file(GLOB_RECURSE gfiles "${target_dir}/*.gcda")
list(LENGTH gfiles len)
# if we have gcda files then also grab the labels file for that target
if(${len} GREATER 0)
@@ -132,27 +132,21 @@ function(ctest_coverage_collect_gcov)
# setup the dir for the coverage files
set(coverage_dir "${binary_dir}/Testing/CoverageInfo")
file(MAKE_DIRECTORY "${coverage_dir}")
- # call gcov on each .gcda file
- foreach (gcda_file ${gcda_files})
- # get the directory of the gcda file
- get_filename_component(gcda_file ${binary_dir}/${gcda_file} ABSOLUTE)
- get_filename_component(gcov_dir ${gcda_file} DIRECTORY)
- # run gcov, this will produce the .gcov file in the current
- # working directory
- if(NOT DEFINED GCOV_GCOV_OPTIONS)
- set(GCOV_GCOV_OPTIONS -b)
- endif()
- execute_process(COMMAND
- ${gcov_command} ${GCOV_GCOV_OPTIONS} -o ${gcov_dir} ${gcda_file}
- OUTPUT_VARIABLE out
- RESULT_VARIABLE res
- WORKING_DIRECTORY ${coverage_dir})
-
- if (GCOV_DELETE)
- file(REMOVE ${gcda_file})
- endif()
+ # run gcov, this will produce the .gcov files in the current
+ # working directory
+ if(NOT DEFINED GCOV_GCOV_OPTIONS)
+ set(GCOV_GCOV_OPTIONS -b -x)
+ endif()
+ execute_process(COMMAND
+ ${gcov_command} ${GCOV_GCOV_OPTIONS} ${gcda_files}
+ OUTPUT_VARIABLE out
+ RESULT_VARIABLE res
+ WORKING_DIRECTORY ${coverage_dir})
+
+ if (GCOV_DELETE)
+ file(REMOVE ${gcda_files})
+ endif()
- endforeach()
if(NOT "${res}" EQUAL 0)
if (NOT GCOV_QUIET)
message(STATUS "Error running gcov: ${res} ${out}")
diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
index f5c112717..a3e2da368 100644
--- a/Modules/CheckCCompilerFlag.cmake
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -37,27 +37,27 @@ include(CheckCSourceCompiles)
include(CMakeCheckCompilerFlagCommonPatterns)
macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
- set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
- set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+ set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
# Normalize locale during test compilation.
- set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
- foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
- set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}")
- set(ENV{${v}} C)
- endforeach()
- CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS)
- CHECK_C_SOURCE_COMPILES("int main(void) { return 0; }" ${_RESULT}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU
- ${_CheckCCompilerFlag_COMMON_PATTERNS}
- )
- foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
- set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}})
- unset(_CheckCCompilerFlag_SAVED_${v})
- endforeach()
- unset(_CheckCCompilerFlag_LOCALE_VARS)
- unset(_CheckCCompilerFlag_COMMON_PATTERNS)
-
- set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
+ foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
+ set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}")
+ set(ENV{${v}} C)
+ endforeach()
+ CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS)
+ CHECK_C_SOURCE_COMPILES("int main(void) { return 0; }" ${_RESULT}
+ # Some compilers do not fail with a bad flag
+ FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU
+ ${_CheckCCompilerFlag_COMMON_PATTERNS}
+ )
+ foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
+ set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}})
+ unset(_CheckCCompilerFlag_SAVED_${v})
+ endforeach()
+ unset(_CheckCCompilerFlag_LOCALE_VARS)
+ unset(_CheckCCompilerFlag_COMMON_PATTERNS)
+
+ set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
endmacro ()
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
index a01e142ab..5729843c3 100644
--- a/Modules/CheckCXXCompilerFlag.cmake
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -37,27 +37,27 @@ include(CheckCXXSourceCompiles)
include(CMakeCheckCompilerFlagCommonPatterns)
macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
- set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
- set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
- # Normalize locale during test compilation.
- set(_CheckCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
- foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
- set(_CheckCXXCompilerFlag_SAVED_${v} "$ENV{${v}}")
- set(ENV{${v}} C)
- endforeach()
- CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCXXCompilerFlag_COMMON_PATTERNS)
- CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" ${_RESULT}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
- ${_CheckCXXCompilerFlag_COMMON_PATTERNS}
- )
- foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
- set(ENV{${v}} ${_CheckCXXCompilerFlag_SAVED_${v}})
- unset(_CheckCXXCompilerFlag_SAVED_${v})
- endforeach()
- unset(_CheckCXXCompilerFlag_LOCALE_VARS)
- unset(_CheckCXXCompilerFlag_COMMON_PATTERNS)
-
- set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+
+ # Normalize locale during test compilation.
+ set(_CheckCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
+ foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
+ set(_CheckCXXCompilerFlag_SAVED_${v} "$ENV{${v}}")
+ set(ENV{${v}} C)
+ endforeach()
+ CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCXXCompilerFlag_COMMON_PATTERNS)
+ CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" ${_RESULT}
+ # Some compilers do not fail with a bad flag
+ FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
+ ${_CheckCXXCompilerFlag_COMMON_PATTERNS}
+ )
+ foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
+ set(ENV{${v}} ${_CheckCXXCompilerFlag_SAVED_${v}})
+ unset(_CheckCXXCompilerFlag_SAVED_${v})
+ endforeach()
+ unset(_CheckCXXCompilerFlag_LOCALE_VARS)
+ unset(_CheckCXXCompilerFlag_COMMON_PATTERNS)
+
+ set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
endmacro ()
diff --git a/Modules/CheckCXXSymbolExists.cmake b/Modules/CheckCXXSymbolExists.cmake
index 970e301b4..2cccd09ff 100644
--- a/Modules/CheckCXXSymbolExists.cmake
+++ b/Modules/CheckCXXSymbolExists.cmake
@@ -24,7 +24,7 @@ Check if a symbol exists as a function, variable, or macro in C++
as a function or variable then the symbol must also be available for
linking. If the symbol is a type or enum value it will not be
recognized (consider using :module:`CheckTypeSize`
- or :module:`CheckCSourceCompiles`).
+ or :module:`CheckCXXSourceCompiles`).
The following variables may be set before calling this macro to modify
the way the check is run:
diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake
index efa88bdab..a1a3a7aac 100644
--- a/Modules/CheckLanguage.cmake
+++ b/Modules/CheckLanguage.cmake
@@ -13,12 +13,14 @@ Usage:
check_language(<lang>)
-where <lang> is a language that may be passed to enable_language()
-such as "Fortran". If CMAKE_<lang>_COMPILER is already defined the
-check does nothing. Otherwise it tries enabling the language in a
-test project. The result is cached in CMAKE_<lang>_COMPILER as the
-compiler that was found, or NOTFOUND if the language cannot be
-enabled.
+where ``<lang>`` is a language that may be passed to :command:`enable_language`
+such as ``Fortran``. If :variable:`CMAKE_<LANG>_COMPILER` is already defined
+the check does nothing. Otherwise it tries enabling the language in a
+test project. The result is cached in :variable:`CMAKE_<LANG>_COMPILER`
+as the compiler that was found, or ``NOTFOUND`` if the language cannot be
+enabled. For CUDA which can have an explicit host compiler, the cache
+:variable:`CMAKE_CUDA_HOST_COMPILER` variable will be set if it was required
+for compilation.
Example:
@@ -39,13 +41,23 @@ macro(check_language lang)
set(_desc "Looking for a ${lang} compiler")
message(STATUS ${_desc})
file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang})
- file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt"
+
+ set(extra_compiler_variables)
+ if(lang STREQUAL CUDA)
+ set(extra_compiler_variables "set(CMAKE_CUDA_HOST_COMPILER \\\"\${CMAKE_CUDA_HOST_COMPILER}\\\")")
+ endif()
+
+ set(content
"cmake_minimum_required(VERSION ${CMAKE_VERSION})
project(Check${lang} ${lang})
file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
\"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\"
- )
-")
+ \"${extra_compiler_variables}\\n\"
+ )"
+ )
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt"
+ "${content}")
if(CMAKE_GENERATOR_INSTANCE)
set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
else()
@@ -75,5 +87,12 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
message(STATUS "${_desc} - ${CMAKE_${lang}_COMPILER}")
set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler")
mark_as_advanced(CMAKE_${lang}_COMPILER)
+
+ if(CMAKE_${lang}_HOST_COMPILER)
+ message(STATUS "Looking for a ${lang} host compiler - ${CMAKE_${lang}_HOST_COMPILER}")
+ set(CMAKE_${lang}_HOST_COMPILER "${CMAKE_${lang}_HOST_COMPILER}" CACHE FILEPATH "${lang} host compiler")
+ mark_as_advanced(CMAKE_${lang}_HOST_COMPILER)
+ endif()
+
endif()
endmacro()
diff --git a/Modules/CheckPIESupported.cmake b/Modules/CheckPIESupported.cmake
index 720217db6..6d63f0bad 100644
--- a/Modules/CheckPIESupported.cmake
+++ b/Modules/CheckPIESupported.cmake
@@ -5,8 +5,8 @@
CheckPIESupported
-----------------
-Check whether the linker supports position independent code (PIE) or no
-position independent code (NO_PIE) for executables.
+Check whether the linker supports Position Independent Code (PIE) or No
+Position Independent Code (NO_PIE) for executables.
Use this to ensure that the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
property for executables will be honored at link time.
diff --git a/Modules/CheckStructHasMember.cmake b/Modules/CheckStructHasMember.cmake
index 7fef85770..842a8fdb7 100644
--- a/Modules/CheckStructHasMember.cmake
+++ b/Modules/CheckStructHasMember.cmake
@@ -50,33 +50,33 @@ include(CheckCSourceCompiles)
include(CheckCXXSourceCompiles)
macro (CHECK_STRUCT_HAS_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
- set(_INCLUDE_FILES)
- foreach (it ${_HEADER})
- string(APPEND _INCLUDE_FILES "#include <${it}>\n")
- endforeach ()
-
- if("x${ARGN}" STREQUAL "x")
- set(_lang C)
- elseif("x${ARGN}" MATCHES "^xLANGUAGE;([a-zA-Z]+)$")
- set(_lang "${CMAKE_MATCH_1}")
- else()
- message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n")
- endif()
-
- set(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
+ set(_INCLUDE_FILES)
+ foreach (it ${_HEADER})
+ string(APPEND _INCLUDE_FILES "#include <${it}>\n")
+ endforeach ()
+
+ if("x${ARGN}" STREQUAL "x")
+ set(_lang C)
+ elseif("x${ARGN}" MATCHES "^xLANGUAGE;([a-zA-Z]+)$")
+ set(_lang "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n")
+ endif()
+
+ set(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
${_INCLUDE_FILES}
int main()
{
- (void)sizeof(((${_STRUCT} *)0)->${_MEMBER});
- return 0;
+ (void)sizeof(((${_STRUCT} *)0)->${_MEMBER});
+ return 0;
}
")
- if("${_lang}" STREQUAL "C")
- CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
- elseif("${_lang}" STREQUAL "CXX")
- CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
- else()
- message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n")
- endif()
+ if("${_lang}" STREQUAL "C")
+ CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
+ elseif("${_lang}" STREQUAL "CXX")
+ CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
+ else()
+ message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n")
+ endif()
endmacro ()
diff --git a/Modules/CheckTypeSize.c.in b/Modules/CheckTypeSize.c.in
index 2303c4e05..82035a336 100644
--- a/Modules/CheckTypeSize.c.in
+++ b/Modules/CheckTypeSize.c.in
@@ -18,7 +18,7 @@
#endif
#define SIZE (sizeof(@type@))
-char info_size[] = {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',
+static char info_size[] = {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',
('0' + ((SIZE / 10000)%10)),
('0' + ((SIZE / 1000)%10)),
('0' + ((SIZE / 100)%10)),
diff --git a/Modules/Compiler/ARMCC-ASM.cmake b/Modules/Compiler/ARMCC-ASM.cmake
index 539d5259f..5819fc756 100644
--- a/Modules/Compiler/ARMCC-ASM.cmake
+++ b/Modules/Compiler/ARMCC-ASM.cmake
@@ -4,4 +4,4 @@ set(CMAKE_ASM_OUTPUT_EXTENSION ".o")
set(CMAKE_ASM_OUTPUT_EXTENSION_REPLACE 1)
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
-set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS S;s;asm;msa)
diff --git a/Modules/Compiler/ARMClang-ASM.cmake b/Modules/Compiler/ARMClang-ASM.cmake
new file mode 100644
index 000000000..ceff3e8ce
--- /dev/null
+++ b/Modules/Compiler/ARMClang-ASM.cmake
@@ -0,0 +1,9 @@
+include(Compiler/ARMClang)
+
+set(CMAKE_ASM_OUTPUT_EXTENSION ".o")
+set(CMAKE_ASM_OUTPUT_EXTENSION_REPLACE 1)
+
+set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> <INCLUDES> <FLAGS> -c -o <OBJECT> <SOURCE>")
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS S;s;asm;msa)
+
+__compiler_armclang(ASM)
diff --git a/Modules/Compiler/ARMClang-C-FeatureTests.cmake b/Modules/Compiler/ARMClang-C-FeatureTests.cmake
new file mode 100644
index 000000000..ef79229d0
--- /dev/null
+++ b/Modules/Compiler/ARMClang-C-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-C-FeatureTests)
diff --git a/Modules/Compiler/ARMClang-C.cmake b/Modules/Compiler/ARMClang-C.cmake
new file mode 100644
index 000000000..0a64a8a4f
--- /dev/null
+++ b/Modules/Compiler/ARMClang-C.cmake
@@ -0,0 +1,15 @@
+include(Compiler/Clang-C)
+include(Compiler/ARMClang)
+__compiler_armclang(C)
+
+set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+
+set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+
+set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
diff --git a/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake b/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake
new file mode 100644
index 000000000..e038e807b
--- /dev/null
+++ b/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-CXX-FeatureTests)
diff --git a/Modules/Compiler/ARMClang-CXX.cmake b/Modules/Compiler/ARMClang-CXX.cmake
new file mode 100644
index 000000000..5dfb4011e
--- /dev/null
+++ b/Modules/Compiler/ARMClang-CXX.cmake
@@ -0,0 +1,3 @@
+include(Compiler/Clang-CXX)
+include(Compiler/ARMClang)
+__compiler_armclang(CXX)
diff --git a/Modules/Compiler/ARMClang-DetermineCompiler.cmake b/Modules/Compiler/ARMClang-DetermineCompiler.cmake
new file mode 100644
index 000000000..eb0de5306
--- /dev/null
+++ b/Modules/Compiler/ARMClang-DetermineCompiler.cmake
@@ -0,0 +1,10 @@
+# ARMClang Toolchain
+set(_compiler_id_pp_test "defined(__clang__) && defined(__ARMCOMPILER_VERSION)")
+
+set(_compiler_id_version_compute "
+ # define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ARMCOMPILER_VERSION/1000000)
+ # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ARMCOMPILER_VERSION/10000 % 100)
+ # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ARMCOMPILER_VERSION % 10000)")
+
+string(APPEND _compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__ARMCOMPILER_VERSION)")
diff --git a/Modules/Compiler/ARMClang.cmake b/Modules/Compiler/ARMClang.cmake
new file mode 100644
index 000000000..2518ac714
--- /dev/null
+++ b/Modules/Compiler/ARMClang.cmake
@@ -0,0 +1,71 @@
+if(_ARMClang_CMAKE_LOADED)
+ return()
+endif()
+set(_ARMClang_CMAKE_LOADED TRUE)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+get_filename_component(_CMAKE_C_TOOLCHAIN_LOCATION "${CMAKE_C_COMPILER}" PATH)
+get_filename_component(_CMAKE_CXX_TOOLCHAIN_LOCATION "${CMAKE_CXX_COMPILER}" PATH)
+
+set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+
+find_program(CMAKE_ARMClang_LINKER armlink HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+find_program(CMAKE_ARMClang_AR armar HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+
+set(CMAKE_LINKER "${CMAKE_ARMClang_LINKER}" CACHE FILEPATH "The ARMClang linker" FORCE)
+mark_as_advanced(CMAKE_ARMClang_LINKER)
+set(CMAKE_AR "${CMAKE_ARMClang_AR}" CACHE FILEPATH "The ARMClang archiver" FORCE)
+mark_as_advanced(CMAKE_ARMClang_AR)
+
+# get compiler supported cpu list
+function(__armclang_set_processor_list lang out_var)
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" --target=${CMAKE_${lang}_COMPILER_TARGET} -mcpu=list
+ OUTPUT_VARIABLE processor_list
+ ERROR_VARIABLE processor_list)
+ string(REGEX MATCHALL "-mcpu=([^ \n]*)" processor_list "${processor_list}")
+ string(REGEX REPLACE "-mcpu=" "" processor_list "${processor_list}")
+ set(${out_var} "${processor_list}" PARENT_SCOPE)
+endfunction()
+
+# check processor is in list
+function(__armclang_check_processor processor list out_var)
+ string(TOLOWER "${processor}" processor)
+ if(processor IN_LIST list)
+ set(${out_var} TRUE PARENT_SCOPE)
+ else()
+ set(${out_var} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(__compiler_armclang lang)
+ if(NOT CMAKE_${lang}_COMPILER_TARGET)
+ set(CMAKE_${lang}_COMPILER_TARGET arm-arm-none-eabi)
+ endif()
+ if(NOT CMAKE_${lang}_COMPILER_PROCESSOR_LIST)
+ __armclang_set_processor_list(${lang} CMAKE_${lang}_COMPILER_PROCESSOR_LIST)
+ endif()
+ if(NOT CMAKE_SYSTEM_PROCESSOR)
+ message(FATAL_ERROR " CMAKE_SYSTEM_PROCESSOR must be set for ARMClang\n"
+ " Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n")
+ else()
+ __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}" _CMAKE_${lang}_CHECK_RESULT)
+ if(NOT _CMAKE_${lang}_CHECK_RESULT)
+ message(FATAL_ERROR " System processor '${CMAKE_SYSTEM_PROCESSOR}' not supported by ARMClang ${lang} compiler\n"
+ " Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n")
+ endif()
+ unset(_CMAKE_${lang}_CHECK_RESULT)
+ endif()
+ string(APPEND CMAKE_${lang}_FLAGS_INIT "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
+ string(APPEND CMAKE_${lang}_LINK_FLAGS "--cpu=${CMAKE_SYSTEM_PROCESSOR}")
+
+ 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_${lang}_ARCHIVE_CREATE "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "--via=")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION_REPLACE 1)
+endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/Compiler/AppleClang-C.cmake b/Modules/Compiler/AppleClang-C.cmake
index a48adec92..2794f52bb 100644
--- a/Modules/Compiler/AppleClang-C.cmake
+++ b/Modules/Compiler/AppleClang-C.cmake
@@ -4,12 +4,15 @@ __compiler_clang(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")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif()
__compiler_check_default_language_standard(C 4.0 99)
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index e5fd64721..3fa69904a 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -8,6 +8,7 @@ endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
@@ -16,10 +17,12 @@ endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
# AppleClang 5.0 knows this flag, but does not set a __cplusplus macro greater than 201103L
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
endif()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
@@ -27,4 +30,13 @@ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
endif()
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+endif()
+
__compiler_check_default_language_standard(CXX 4.0 98)
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index ad464c77c..96537f8dd 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -65,13 +65,28 @@ endmacro()
macro(cmake_record_c_compile_features)
set(_result 0)
if(_result EQUAL 0 AND DEFINED CMAKE_C11_STANDARD_COMPILE_OPTION)
- _record_compiler_features_c(11)
+ if(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(11)
+ else()
+ _record_compiler_features_c(11)
+ endif()
+ unset(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_C99_STANDARD_COMPILE_OPTION)
- _record_compiler_features_c(99)
+ if(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(99)
+ else()
+ _record_compiler_features_c(99)
+ endif()
+ unset(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_C90_STANDARD_COMPILE_OPTION)
- _record_compiler_features_c(90)
+ if(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(90)
+ else()
+ _record_compiler_features_c(90)
+ endif()
+ unset(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
endif()
endmacro()
@@ -79,18 +94,43 @@ endmacro()
macro(cmake_record_cxx_compile_features)
set(_result 0)
if(_result EQUAL 0 AND DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION)
- _record_compiler_features_cxx(20)
+ 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)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_CXX17_STANDARD_COMPILE_OPTION)
- _record_compiler_features_cxx(17)
+ 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)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_CXX14_STANDARD_COMPILE_OPTION)
- _record_compiler_features_cxx(14)
+ if(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(14)
+ else()
+ _record_compiler_features_cxx(14)
+ endif()
+ unset(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION)
- _record_compiler_features_cxx(11)
+ if(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(11)
+ else()
+ _record_compiler_features_cxx(11)
+ endif()
+ unset(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
endif()
if(_result EQUAL 0 AND DEFINED CMAKE_CXX98_STANDARD_COMPILE_OPTION)
- _record_compiler_features_cxx(98)
+ if(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(98)
+ else()
+ _record_compiler_features_cxx(98)
+ endif()
+ unset(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
endif()
endmacro()
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index a07ae4019..0448965ee 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -10,22 +10,28 @@ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
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_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
else()
# clang-cl doesn't have any of these
set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif()
endif()
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index e99011b3b..17f391746 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -1,7 +1,7 @@
include(Compiler/Clang)
__compiler_clang(CXX)
-if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
endif()
@@ -10,15 +10,18 @@ if(APPLE AND NOT appleClangPolicy STREQUAL NEW)
return()
endif()
-if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.1)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
@@ -27,9 +30,11 @@ if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
endif()
set(_clang_version_std17 5.0)
@@ -52,6 +57,14 @@ if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
unset(_clang_version_std17)
+ if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ # This clang++ is missing some features because of MSVC compatibility.
+ unset(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
+ unset(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
+ unset(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT)
+ unset(CMAKE_CXX20_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+
__compiler_check_default_language_standard(CXX 2.1 98)
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9
AND CMAKE_CXX_SIMULATE_VERSION VERSION_GREATER_EQUAL 19.0)
@@ -59,6 +72,7 @@ elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9
# support for -std: flags.
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
diff --git a/Modules/Compiler/Cray-C.cmake b/Modules/Compiler/Cray-C.cmake
index d34154c1f..93409489b 100644
--- a/Modules/Compiler/Cray-C.cmake
+++ b/Modules/Compiler/Cray-C.cmake
@@ -10,11 +10,14 @@ string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
set(CMAKE_C90_STANDARD_COMPILE_OPTION -h noc99,conform)
set(CMAKE_C90_EXTENSION_COMPILE_OPTION -h noc99,gnu)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION -h c99,conform)
set(CMAKE_C99_EXTENSION_COMPILE_OPTION -h c99,gnu)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.5)
set(CMAKE_C11_STANDARD_COMPILE_OPTION -h std=c11,conform)
set(CMAKE_C11_EXTENSION_COMPILE_OPTION -h std=c11,gnu)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif ()
endif ()
diff --git a/Modules/Compiler/Cray-CXX.cmake b/Modules/Compiler/Cray-CXX.cmake
index 85a316793..38c8b1ee9 100644
--- a/Modules/Compiler/Cray-CXX.cmake
+++ b/Modules/Compiler/Cray-CXX.cmake
@@ -10,13 +10,16 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION -h conform)
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -h gnu)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.4)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION -h std=c++11)
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -h std=c++11,gnu)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.6)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION -h std=c++14)
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -h std=c++14,gnu)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
endif ()
endif ()
diff --git a/Modules/Compiler/Cray-Fortran.cmake b/Modules/Compiler/Cray-Fortran.cmake
index dbf28e3a4..ccb7c2ee5 100644
--- a/Modules/Compiler/Cray-Fortran.cmake
+++ b/Modules/Compiler/Cray-Fortran.cmake
@@ -4,6 +4,8 @@
include(Compiler/Cray)
__compiler_cray(Fortran)
+set(CMAKE_Fortran_SUBMODULE_SEP "")
+set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
set(CMAKE_Fortran_MODOUT_FLAG -em)
set(CMAKE_Fortran_MODDIR_FLAG -J)
set(CMAKE_Fortran_MODDIR_DEFAULT .)
diff --git a/Modules/Compiler/CrayPrgEnv.cmake b/Modules/Compiler/CrayPrgEnv.cmake
index 6c1c77016..e55e5873a 100644
--- a/Modules/Compiler/CrayPrgEnv.cmake
+++ b/Modules/Compiler/CrayPrgEnv.cmake
@@ -1,8 +1,93 @@
# Guard against multiple inclusions
-if(__craylinux_crayprgenv)
+if(__cmake_craype_crayprgenv)
return()
endif()
-set(__craylinux_crayprgenv 1)
+set(__cmake_craype_crayprgenv 1)
+
+# CrayPrgEnv: loaded when compiling through the Cray compiler wrapper.
+# The compiler wrapper can run on a front-end node or a compute node.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+# One-time setup of the craype environment. First, check the wrapper config.
+# The wrapper's selection of a compiler (gcc, clang, intel, etc.) and
+# default include/library paths is selected using the "module" command.
+# The CRAYPE_LINK_TYPE environment variable partly controls if static
+# or dynamic binaries are generated (see __cmake_craype_linktype below).
+# Running cmake and then changing module and/or linktype configuration
+# may cause build problems (since the data in the cmake cache may no
+# longer be correct after the change). We can look for this and warn
+# the user about it. Second, use the "module" provided PKG_CONFIG_PATH-like
+# environment variable to add additional prefixes to the system prefix
+# path.
+function(__cmake_craype_setupenv)
+ if(NOT DEFINED __cmake_craype_setupenv_done) # only done once per run
+ set(__cmake_craype_setupenv_done 1 PARENT_SCOPE)
+ unset(__cmake_check)
+ set(CMAKE_CRAYPE_LINKTYPE "$ENV{CRAYPE_LINK_TYPE}" CACHE STRING
+ "saved value of CRAYPE_LINK_TYPE environment variable")
+ set(CMAKE_CRAYPE_LOADEDMODULES "$ENV{LOADEDMODULES}" CACHE STRING
+ "saved value of LOADEDMODULES environment variable")
+ mark_as_advanced(CMAKE_CRAYPE_LINKTYPE CMAKE_CRAYPE_LOADEDMODULES)
+ if (NOT "${CMAKE_CRAYPE_LINKTYPE}" STREQUAL "$ENV{CRAYPE_LINK_TYPE}")
+ string(APPEND __cmake_check "CRAYPE_LINK_TYPE ")
+ endif()
+ if (NOT "${CMAKE_CRAYPE_LOADEDMODULES}" STREQUAL "$ENV{LOADEDMODULES}")
+ string(APPEND __cmake_check "LOADEDMODULES ")
+ endif()
+ if(DEFINED __cmake_check)
+ message(STATUS "NOTE: ${__cmake_check}changed since initial config!")
+ message(STATUS "NOTE: this may cause unexpected build errors.")
+ endif()
+ # loop over variables of interest
+ foreach(pkgcfgvar PKG_CONFIG_PATH PKG_CONFIG_PATH_DEFAULT
+ PE_PKG_CONFIG_PATH)
+ file(TO_CMAKE_PATH "$ENV{${pkgcfgvar}}" pkgcfg)
+ foreach(path ${pkgcfg})
+ string(REGEX REPLACE "(.*)/lib[^/]*/pkgconfig$" "\\1" path "${path}")
+ if(NOT "${path}" STREQUAL "" AND
+ NOT "${path}" IN_LIST CMAKE_SYSTEM_PREFIX_PATH)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${path}")
+ endif()
+ endforeach()
+ endforeach()
+ # push it up out of this function into the parent scope
+ set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# The wrapper disables dynamic linking by default. Dynamic linking is
+# enabled either by setting $ENV{CRAYPE_LINK_TYPE} to "dynamic" or by
+# specifying "-dynamic" to the wrapper when linking. Specifying "-static"
+# to the wrapper when linking takes priority over $ENV{CRAYPE_LINK_TYPE}.
+# Furthermore, if you specify multiple "-dynamic" and "-static" flags to
+# the wrapper when linking, the last one will win. In this case, the
+# wrapper will also print a warning like:
+# Warning: -dynamic was already seen on command line, overriding with -static.
+#
+# note that cmake applies both CMAKE_${lang}_FLAGS and CMAKE_EXE_LINKER_FLAGS
+# (in that order) to the linking command, so -dynamic can appear in either
+# variable.
+function(__cmake_craype_linktype lang rv)
+ # start with ENV, but allow flags to override
+ if("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "dynamic")
+ set(linktype dynamic)
+ else()
+ set(linktype static)
+ endif()
+ # combine flags and convert to a list so we can apply the flags in order
+ set(linkflags "${CMAKE_${lang}_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}")
+ string(REPLACE " " ";" linkflags "${linkflags}")
+ foreach(flag IN LISTS linkflags)
+ if("${flag}" STREQUAL "-dynamic")
+ set(linktype dynamic)
+ elseif("${flag}" STREQUAL "-static")
+ set(linktype static)
+ endif()
+ endforeach()
+ set(${rv} ${linktype} PARENT_SCOPE)
+endfunction()
macro(__CrayPrgEnv_setup lang)
if(DEFINED ENV{CRAYPE_VERSION})
@@ -13,25 +98,25 @@ macro(__CrayPrgEnv_setup lang)
message(STATUS "Cray Programming Environment (unknown version) ${lang}")
endif()
+ # setup the craype environment
+ __cmake_craype_setupenv()
+
# Flags for the Cray wrappers
set(CMAKE_STATIC_LIBRARY_LINK_${lang}_FLAGS "-static")
set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-dynamic")
- # If the link type is not explicitly specified in the environment then
- # the Cray wrappers assume that the code will be built statically so
- # we check the following condition(s) are NOT met
- # Compiler flags are explicitly dynamic
- # Env var is dynamic and compiler flags are not explicitly static
- if(NOT (((CMAKE_${lang}_FLAGS MATCHES "(^| )-dynamic($| )") OR
- (CMAKE_EXE_LINKER_FLAGS MATCHES "(^| )-dynamic($| )"))
- OR
- (("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "dynamic") AND
- NOT ((CMAKE_${lang}_FLAGS MATCHES "(^| )-static($| )") OR
- (CMAKE_EXE_LINKER_FLAGS MATCHES "(^| )-static($| )")))))
+ # determine linktype from environment and compiler flags
+ __cmake_craype_linktype(${lang} __cmake_craype_${lang}_linktype)
+
+ # switch off shared libs if we get a static linktype
+ if("${__cmake_craype_${lang}_linktype}" STREQUAL "static")
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
set(BUILD_SHARED_LIBS FALSE CACHE BOOL "")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(CMAKE_LINK_SEARCH_START_STATIC TRUE)
endif()
+
endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake
index f072c546a..ca286b397 100644
--- a/Modules/Compiler/GNU-C.cmake
+++ b/Modules/Compiler/GNU-C.cmake
@@ -10,13 +10,16 @@ elseif (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
endif()
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
endif()
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
elseif (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c1x")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake
index 00582236a..fcaaeab43 100644
--- a/Modules/Compiler/GNU-CXX.cmake
+++ b/Modules/Compiler/GNU-CXX.cmake
@@ -17,6 +17,7 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
endif()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
@@ -25,6 +26,10 @@ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
endif()
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.1)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
@@ -33,6 +38,10 @@ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
endif()
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
diff --git a/Modules/Compiler/GNU-FindBinUtils.cmake b/Modules/Compiler/GNU-FindBinUtils.cmake
index 16b7bbda4..097fbf3ac 100644
--- a/Modules/Compiler/GNU-FindBinUtils.cmake
+++ b/Modules/Compiler/GNU-FindBinUtils.cmake
@@ -18,7 +18,7 @@ get_filename_component(__gcc_hints "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPIL
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x_y}"
"${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x}"
- "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar${_CMAKE_COMPILER_SUFFIX}"
HINTS ${__gcc_hints}
DOC "A wrapper around 'ar' adding the appropriate '--plugin' option for the GCC compiler"
)
@@ -28,7 +28,7 @@ mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR)
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x_y}"
"${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x}"
- "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib${_CMAKE_COMPILER_SUFFIX}"
HINTS ${__gcc_hints}
DOC "A wrapper around 'ranlib' adding the appropriate '--plugin' option for the GCC compiler"
)
diff --git a/Modules/Compiler/IAR-ASM.cmake b/Modules/Compiler/IAR-ASM.cmake
index e12bfd18e..437678e19 100644
--- a/Modules/Compiler/IAR-ASM.cmake
+++ b/Modules/Compiler/IAR-ASM.cmake
@@ -3,21 +3,40 @@
include(Compiler/IAR)
if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
- __compiler_iar_ARM(ASM)
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ 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)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ 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)
- string(APPEND CMAKE_ASM_FLAGS_INIT " ")
- string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
- string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
- string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
- string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ 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)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISC-V")
+ 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)
elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
- __compiler_iar_AVR(ASM)
+ __compiler_iar_xlink(ASM)
set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa)
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_xlink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s43;asm;msa)
+
else()
- message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\". This should be automatic.")
+ message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
endif()
diff --git a/Modules/Compiler/IAR-C.cmake b/Modules/Compiler/IAR-C.cmake
index b5e61f070..18a4a7581 100644
--- a/Modules/Compiler/IAR-C.cmake
+++ b/Modules/Compiler/IAR-C.cmake
@@ -3,60 +3,63 @@
include(Compiler/IAR)
include(Compiler/CMakeCommonCompilerMacros)
-# The toolchains for ARM and AVR are quite different:
-if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
- if(NOT CMAKE_C_COMPILER_VERSION)
- message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected. This should be automatic.")
- endif()
+# Common
+if(NOT CMAKE_C_COMPILER_VERSION)
+ message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected. This should be automatic.")
+endif()
- set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
+set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
+if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
+elseif()
set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
+endif()
- if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.10)
- set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
- set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
- set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
- set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
- endif()
- if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.10)
- set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
- set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
- endif()
+if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
+endif()
- __compiler_iar_ARM(C)
+# Architecture specific
+if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
+ # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
+ message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+ endif()
+ __compiler_iar_ilink(C)
__compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11)
-elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
- if(NOT CMAKE_C_COMPILER_VERSION)
- message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected. This should be automatic.")
- endif()
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11)
- set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 2.10 11)
- set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
- set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
- set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
- set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 4.10 11)
- __compiler_iar_AVR(C)
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 1.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+ __compiler_iar_xlink(C)
__compiler_check_default_language_standard(C 7.10 99)
set(CMAKE_C_OUTPUT_EXTENSION ".r90")
- if(NOT CMAKE_C_LINK_FLAGS)
- set(CMAKE_C_LINK_FLAGS "-Fmotorola")
- endif()
-
- set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
- set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <OBJECTS> ")
-
- # add the target specific include directory:
- get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH)
- get_filename_component(_compilerDir "${_compilerDir}" PATH)
- include_directories("${_compilerDir}/inc" )
- include_directories("${_compilerDir}/inc/Atmel" )
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_iar_xlink(C)
+ __compiler_check_default_language_standard(C 1.10 90 5.10 99)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r43")
else()
- message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\". This should be automatic.")
+ message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
endif()
diff --git a/Modules/Compiler/IAR-CXX.cmake b/Modules/Compiler/IAR-CXX.cmake
index b7076f5cc..e8f114205 100644
--- a/Modules/Compiler/IAR-CXX.cmake
+++ b/Modules/Compiler/IAR-CXX.cmake
@@ -3,76 +3,71 @@
include(Compiler/IAR)
include(Compiler/CMakeCommonCompilerMacros)
-if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
- # "(extended) embedded C++" Mode
- # old version: --ec++ or --eec++
- # since 8.10: --c++ --no_exceptions --no_rtti
- #
- # --c++ is full C++ and supported since 6.10
- if(NOT CMAKE_IAR_CXX_FLAG)
- if(NOT CMAKE_CXX_COMPILER_VERSION)
- message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
- endif()
- if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.10)
- set(CMAKE_IAR_CXX_FLAG --c++)
- else()
- set(CMAKE_IAR_CXX_FLAG --eec++)
- endif()
+# Common
+if(NOT CMAKE_CXX_COMPILER_VERSION)
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
+endif()
+
+if(NOT CMAKE_IAR_CXX_FLAG)
+ # The --c++ flag was introduced in platform version 9 for all architectures except ARM where it was introduced already in version 7
+ if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8 OR
+ (CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 6 AND "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") )
+ set(CMAKE_IAR_CXX_FLAG --c++)
+ else()
+ set(CMAKE_IAR_CXX_FLAG --eec++)
endif()
+endif()
- set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
+set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
-
- if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.10)
set(CMAKE_CXX03_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX03_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -e)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -e)
- endif()
+endif()
- __compiler_iar_ARM(CXX)
+# Architecture specific
+if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
+ # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+ endif()
+ __compiler_iar_ilink(CXX)
__compiler_check_default_language_standard(CXX 6.10 98 8.10 14)
-elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
- # "embedded C++" --EC++ is probably closest to CXX98 but with no support for:
- # Templates, multiple inheritance, virtual inheritance, exceptions, RTTI, C++ style casts,
- # Namespaces, the mutable attribute, no STL, any library features related to the above features.
- #
- # "(extended) embedded C++" --EEC++ Mode but DOES NOT support any normal C++ standard
- # probably closest to CXX98 but with no RTTI and no exceptions, and the library
- # provided is not in the standard namespace
- if(NOT CMAKE_IAR_CXX_FLAG)
- if(NOT CMAKE_CXX_COMPILER_VERSION)
- message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
- endif()
- set(CMAKE_IAR_CXX_FLAG --eec++)
- endif()
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 2.10 98 4.10 14)
- set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
- set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
- set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 2.10 14)
- __compiler_iar_AVR(CXX)
- __compiler_check_default_language_standard(CXX 7.10 98)
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 4.10 14)
- set(CMAKE_CXX_OUTPUT_EXTENSION ".r90")
- if(NOT CMAKE_CXX_LINK_FLAGS)
- set(CMAKE_CXX_LINK_FLAGS "-Fmotorola")
- endif()
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 1.10 14)
- set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
- set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <OBJECTS> ")
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 7.10 98)
- # add the target specific include directory:
- get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH)
- get_filename_component(_compilerDir "${_compilerDir}" PATH)
- include_directories("${_compilerDir}/inc")
- include_directories("${_compilerDir}/inc/Atmel")
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 5.10 98)
+ set(CMAKE_CXX_OUTPUT_EXTENSION ".r43")
else()
- message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\". This should be automatic." )
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." )
endif()
diff --git a/Modules/Compiler/IAR-DetermineCompiler.cmake b/Modules/Compiler/IAR-DetermineCompiler.cmake
index 43477acb1..57ca1c991 100644
--- a/Modules/Compiler/IAR-DetermineCompiler.cmake
+++ b/Modules/Compiler/IAR-DetermineCompiler.cmake
@@ -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__)
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__))
# 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__)
diff --git a/Modules/Compiler/IAR-FindBinUtils.cmake b/Modules/Compiler/IAR-FindBinUtils.cmake
index 5fecb2662..b7d466405 100644
--- a/Modules/Compiler/IAR-FindBinUtils.cmake
+++ b/Modules/Compiler/IAR-FindBinUtils.cmake
@@ -2,7 +2,7 @@ if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL
message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
endif()
-# Try to find tools in the same directory as Clang itself
+# Try to find tools in the same directory as the compiler itself
get_filename_component(__iar_hint_1 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" REALPATH)
get_filename_component(__iar_hint_1 "${__iar_hint_1}" DIRECTORY)
@@ -10,40 +10,47 @@ get_filename_component(__iar_hint_2 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPI
set(__iar_hints "${__iar_hint_1}" "${__iar_hint_2}")
-if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
- # could allow using normal binutils ar, since objects are normal ELF files?
- find_program(CMAKE_IAR_LINKARM ilinkarm.exe HINTS ${__iar_hints}
- DOC "The IAR ARM linker")
- find_program(CMAKE_IAR_ARCHIVE iarchive.exe HINTS ${__iar_hints}
+if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" OR
+ "${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")
+
+ string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _archid_lower)
+
+ # Find linker
+ find_program(CMAKE_IAR_LINKER ilink${_archid_lower} HINTS ${__iar_hints}
+ DOC "The IAR ILINK linker")
+ find_program(CMAKE_IAR_ARCHIVE iarchive HINTS ${__iar_hints}
DOC "The IAR archiver")
- # find auxiliary tools
- find_program(CMAKE_IAR_ELFTOOL ielftool.exe HINTS ${__iar_hints}
+ # Find utility tools
+ find_program(CMAKE_IAR_ELFTOOL ielftool HINTS ${__iar_hints}
DOC "The IAR ELF Tool")
- find_program(CMAKE_IAR_ELFDUMP ielfdumparm.exe HINTS ${__iar_hints}
+ find_program(CMAKE_IAR_ELFDUMP ielfdump${_archid_lower} HINTS ${__iar_hints}
DOC "The IAR ELF Dumper")
- find_program(CMAKE_IAR_OBJMANIP iobjmanip.exe HINTS ${__iar_hints}
+ find_program(CMAKE_IAR_OBJMANIP iobjmanip HINTS ${__iar_hints}
DOC "The IAR ELF Object Tool")
- find_program(CMAKE_IAR_SYMEXPORT isymexport.exe HINTS ${__iar_hints}
+ find_program(CMAKE_IAR_SYMEXPORT isymexport HINTS ${__iar_hints}
DOC "The IAR Absolute Symbol Exporter")
- mark_as_advanced(CMAKE_IAR_LINKARM CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT)
+ mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT)
set(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CUSTOM_CODE
-"set(CMAKE_IAR_LINKARM \"${CMAKE_IAR_LINKARM}\")
+"set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
set(CMAKE_IAR_ARCHIVE \"${CMAKE_IAR_ARCHIVE}\")
set(CMAKE_IAR_ELFTOOL \"${CMAKE_IAR_ELFTOOL}\")
set(CMAKE_IAR_ELFDUMP \"${CMAKE_IAR_ELFDUMP}\")
set(CMAKE_IAR_OBJMANIP \"${CMAKE_IAR_OBJMANIP}\")
-set(CMAKE_IAR_LINKARM \"${CMAKE_IAR_LINKARM}\")
+set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
")
+elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
-elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
-
- # For AVR and AVR32, IAR uses the "xlink" linker and the "xar" archiver:
- find_program(CMAKE_IAR_LINKER xlink.exe HINTS ${__iar_hints}
- DOC "The IAR AVR linker")
- find_program(CMAKE_IAR_AR xar.exe HINTS ${__iar_hints}
+ # Find the "xlink" linker and "xar" archiver:
+ find_program(CMAKE_IAR_LINKER xlink HINTS ${__iar_hints}
+ DOC "The IAR XLINK linker")
+ find_program(CMAKE_IAR_AR xar HINTS ${__iar_hints}
DOC "The IAR archiver")
mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR)
diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake
index bbcdea235..8e75caafe 100644
--- a/Modules/Compiler/IAR.cmake
+++ b/Modules/Compiler/IAR.cmake
@@ -2,11 +2,16 @@
# Documentation can be downloaded here: http://www.iar.com/website1/1.0.1.0/675/1/
# The initial feature request is here: https://gitlab.kitware.com/cmake/cmake/issues/10176
# It also contains additional links and information.
-# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for:
+# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for EWARM:
# version 6.30.8: http://supp.iar.com/FilesPublic/UPDINFO/006607/arm/doc/infocenter/index.ENU.html
# version 7.60.1: http://supp.iar.com/FilesPublic/UPDINFO/011006/arm/doc/infocenter/index.ENU.html
# version 8.10.1: http://netstorage.iar.com/SuppDB/Public/UPDINFO/011854/arm/doc/infocenter/index.ENU.html
+# The IAR internal compiler platform generations (Predefined symbol __IAR_SYSTEMS_ICC__):
+# 9 and higher means C11 and C++14 as language default (EWARM v8.x, EWRX v4.x and higher)
+# 8 means C99 and C++03 as language default (EWARM v6.x, v7.x. EWRX v2.x, 3.x)
+# 7 and lower means C89 and EC++ as language default. (EWARM v5.x and lower)
+
# C/C++ Standard versions
#
# IAR typically only supports one C and C++ Standard version,
@@ -33,15 +38,11 @@
# code and data size printouts (that can be inspected with common tools).
# This module is shared by multiple languages; use include blocker.
-if(_IARARM_CMAKE_LOADED)
- return()
-endif()
-set(_IARARM_CMAKE_LOADED 1)
+include_guard()
-macro(__compiler_iar_ARM lang)
+macro(__compiler_iar_ilink lang)
set(CMAKE_EXECUTABLE_SUFFIX ".elf")
if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
-
set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
@@ -56,17 +57,25 @@ macro(__compiler_iar_ARM lang)
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
endif()
- set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKARM}\" --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
+ if (${lang} STREQUAL "ASM")
+ string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+ string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+ endif()
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_APPEND "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --replace <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_FINISH "")
- set(CMAKE_LINKER "${CMAKE_IAR_LINKARM}" CACHE FILEPATH "The IAR linker" FORCE)
+ set(CMAKE_LINKER "${CMAKE_IAR_LINKER}" CACHE FILEPATH "The IAR linker" FORCE)
set(CMAKE_AR "${CMAKE_IAR_ARCHIVE}" CACHE FILEPATH "The IAR archiver" FORCE)
endmacro()
-macro(__compiler_iar_AVR lang)
+macro(__compiler_iar_xlink lang)
set(CMAKE_EXECUTABLE_SUFFIX ".bin")
if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
@@ -84,6 +93,14 @@ macro(__compiler_iar_AVR lang)
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
endif()
+ if (${lang} STREQUAL "ASM")
+ string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+ string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+ endif()
+
set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_AR}\" <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_AR}\" <TARGET> <LINK_FLAGS> <OBJECTS>")
diff --git a/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
index e5b97412e..899e284ad 100644
--- a/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
+++ b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
@@ -1,14 +1,6 @@
set(_compiler_id_version_compute "
-# if defined(__ibmxl__)
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
-# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
-# else
- /* __IBMC__ = VRP */
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMC__/100)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMC__/10 % 10)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMC__ % 10)
-# endif
-")
+ /* __IBMC__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMC__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMC__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMC__ % 10)")
diff --git a/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
index 63c3e32d6..73aa2b4f9 100644
--- a/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
+++ b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
@@ -1,14 +1,6 @@
set(_compiler_id_version_compute "
-# if defined(__ibmxl__)
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
-# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
-# else
- /* __IBMCPP__ = VRP */
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMCPP__/100)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMCPP__/10 % 10)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMCPP__ % 10)
-# endif
-")
+ /* __IBMCPP__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMCPP__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMCPP__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMCPP__ % 10)")
diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake
index 4e4af2956..e9e59a20c 100644
--- a/Modules/Compiler/Intel-C.cmake
+++ b/Modules/Compiler/Intel-C.cmake
@@ -12,13 +12,16 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-Qstd=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-Qstd=c11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif()
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-Qstd=c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-Qstd=c89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-Qstd=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-Qstd=c99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
endif()
else()
@@ -26,13 +29,16 @@ else()
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")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif()
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
endif()
endif()
diff --git a/Modules/Compiler/Intel-CXX-FeatureTests.cmake b/Modules/Compiler/Intel-CXX-FeatureTests.cmake
index aa35b977e..bbefe15de 100644
--- a/Modules/Compiler/Intel-CXX-FeatureTests.cmake
+++ b/Modules/Compiler/Intel-CXX-FeatureTests.cmake
@@ -24,7 +24,7 @@ set(DETECT_CXX14 "((__cplusplus >= 201300L) || ((__cplusplus == 201103L) && !def
unset(DETECT_BUGGY_ICC15)
set(Intel17_CXX14 "__INTEL_COMPILER >= 1700 && ${DETECT_CXX14}")
-set(_cmake_feature_test_cxx_relaxed_constexpr "__cpp_constexpr >= 201304 || (${Intel17_CXX14} && !(__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 5) && !defined(_MSC_VER))")
+set(_cmake_feature_test_cxx_relaxed_constexpr "__cpp_constexpr >= 201304 || (${Intel17_CXX14} && !defined(_MSC_VER))")
set(Intel16_CXX14 "__INTEL_COMPILER >= 1600 && ${DETECT_CXX14}")
set(_cmake_feature_test_cxx_aggregate_default_initializers "${Intel16_CXX14}")
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
index c115b6ade..b630a6bc4 100644
--- a/Modules/Compiler/Intel-CXX.cmake
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -30,6 +30,7 @@ if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
endif()
else()
@@ -39,6 +40,10 @@ else()
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
endif()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0)
@@ -53,6 +58,10 @@ else()
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
endif()
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
@@ -64,6 +73,7 @@ else()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
endif()
endif()
diff --git a/Modules/Compiler/Intel-DetermineCompiler.cmake b/Modules/Compiler/Intel-DetermineCompiler.cmake
index d7e453211..c31aa7752 100644
--- a/Modules/Compiler/Intel-DetermineCompiler.cmake
+++ b/Modules/Compiler/Intel-DetermineCompiler.cmake
@@ -18,9 +18,23 @@ set(_compiler_id_version_compute "
/* _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/MIPSpro-C.cmake b/Modules/Compiler/MIPSpro-C.cmake
deleted file mode 100644
index 675560c2a..000000000
--- a/Modules/Compiler/MIPSpro-C.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set(CMAKE_C_VERBOSE_FLAG "-v")
diff --git a/Modules/Compiler/MIPSpro-CXX.cmake b/Modules/Compiler/MIPSpro-CXX.cmake
deleted file mode 100644
index 9fb191c75..000000000
--- a/Modules/Compiler/MIPSpro-CXX.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set(CMAKE_CXX_VERBOSE_FLAG "-v")
diff --git a/Modules/Compiler/MIPSpro-DetermineCompiler.cmake b/Modules/Compiler/MIPSpro-DetermineCompiler.cmake
deleted file mode 100644
index 9e485532b..000000000
--- a/Modules/Compiler/MIPSpro-DetermineCompiler.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-
-set(_compiler_id_pp_test "defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION)")
-
-set(_compiler_id_version_compute "
-# if defined(_SGI_COMPILER_VERSION)
- /* _SGI_COMPILER_VERSION = VRP */
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_SGI_COMPILER_VERSION/100)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_SGI_COMPILER_VERSION/10 % 10)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_SGI_COMPILER_VERSION % 10)
-# else
- /* _COMPILER_VERSION = VRP */
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_COMPILER_VERSION/100)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_COMPILER_VERSION/10 % 10)
-# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_COMPILER_VERSION % 10)
-# endif")
diff --git a/Modules/Compiler/MIPSpro-Fortran.cmake b/Modules/Compiler/MIPSpro-Fortran.cmake
deleted file mode 100644
index ffceea80d..000000000
--- a/Modules/Compiler/MIPSpro-Fortran.cmake
+++ /dev/null
@@ -1,3 +0,0 @@
-set(CMAKE_Fortran_VERBOSE_FLAG "-v")
-set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixedform")
-set(CMAKE_Fortran_FORMAT_FREE_FLAG "-freeform")
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
index 22c34f80c..20787a399 100644
--- a/Modules/Compiler/MSVC-C.cmake
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -11,8 +11,8 @@ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
# There is no meaningful default for this
set(CMAKE_C_STANDARD_DEFAULT "")
-# There are no C compiler modes so we only need to test features once.
-# Override the default macro for this special case. Pretend that
+# There are no C compiler modes so we hard-code the known compiler supported
+# features. Override the default macro for this special case. Pretend that
# all language standards are available so that at least compilation
# can be attempted.
macro(cmake_record_c_compile_features)
@@ -20,6 +20,19 @@ macro(cmake_record_c_compile_features)
c_std_90
c_std_99
c_std_11
+ c_function_prototypes
)
- _record_compiler_features(C "" CMAKE_C_COMPILE_FEATURES)
+ list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
+ list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99)
+ list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0)
+ list(APPEND CMAKE_C_COMPILE_FEATURES c_variadic_macros)
+ list(APPEND CMAKE_C99_COMPILE_FEATURES c_variadic_macros)
+ endif()
+ set(_result 0) # expected by cmake_determine_compile_features
endmacro()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+ set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Modules/Compiler/MSVC-CXX-FeatureTests.cmake b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake
index 9c604f202..125974a8d 100644
--- a/Modules/Compiler/MSVC-CXX-FeatureTests.cmake
+++ b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake
@@ -9,10 +9,8 @@ set(_cmake_oldestSupported "_MSC_VER >= 1600")
# https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#update_153
set(_cmake_feature_test_cxx_decltype_incomplete_return_types "_MSC_VER >= 1911")
-set(MSVC_2017 "_MSC_VER >= 1910")
-# VS 2017 introduces support for "N3652 Extended constexpr"
-# but as of v15.6 there are still bugs in the implementation
-#set(_cmake_feature_test_cxx_relaxed_constexpr "${MSVC_2017}")
+# VS 2017 v15.3 fixes support for "N3652 Extended constexpr"
+set(_cmake_feature_test_cxx_relaxed_constexpr "_MSC_VER >= 1911")
# VS 2017 Preview introduces support for aggregate initializers.
set(_cmake_feature_test_cxx_aggregate_default_initializers "_MSC_FULL_VER >= 190024406")
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index be259ff6f..915295d38 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -11,11 +11,14 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
# with the default and minimum level being C++14.
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std:c++14")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11.25505)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++17")
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++17")
else()
@@ -29,21 +32,6 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
__compiler_check_default_language_standard(CXX 19.0 14)
- # All features that we define are available in the base mode, except
- # for meta-features for C++14 and above. Override the default macro
- # to avoid doing unnecessary work.
- macro(cmake_record_cxx_compile_features)
- if (DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION)
- list(APPEND CMAKE_CXX20_COMPILE_FEATURES cxx_std_20)
- endif()
- # The main cmake_record_cxx_compile_features macro makes all
- # these conditional on CMAKE_CXX##_STANDARD_COMPILE_OPTION,
- # but we can skip the conditions because we set them above.
- list(APPEND CMAKE_CXX17_COMPILE_FEATURES cxx_std_17)
- list(APPEND CMAKE_CXX14_COMPILE_FEATURES cxx_std_14)
- list(APPEND CMAKE_CXX98_COMPILE_FEATURES cxx_std_11) # no flag needed for 11
- _record_compiler_features_cxx(98)
- endmacro()
elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
# MSVC has no specific options to set language standards, but set them as
# empty strings anyways so the feature test infrastructure can at least check
@@ -77,3 +65,8 @@ elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
_record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES)
endmacro()
endif()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+ set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
index de9dd99ba..c0ccb7147 100644
--- a/Modules/Compiler/NVIDIA-CUDA.cmake
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -40,3 +40,8 @@ endif()
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "9.0")
+ set(CMAKE_CUDA_RESPONSE_FILE_LINK_FLAG "--options-file ")
+ set(CMAKE_CUDA_RESPONSE_FILE_FLAG "--options-file ")
+endif()
diff --git a/Modules/Compiler/PGI-C.cmake b/Modules/Compiler/PGI-C.cmake
index 3b3848a2c..c39dbe517 100644
--- a/Modules/Compiler/PGI-C.cmake
+++ b/Modules/Compiler/PGI-C.cmake
@@ -6,11 +6,14 @@ string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
set(CMAKE_C90_STANDARD_COMPILE_OPTION -c89)
set(CMAKE_C90_EXTENSION_COMPILE_OPTION -c89)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION -c99)
set(CMAKE_C99_EXTENSION_COMPILE_OPTION -c99)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.3)
set(CMAKE_C11_STANDARD_COMPILE_OPTION -c11)
set(CMAKE_C11_EXTENSION_COMPILE_OPTION -c11)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif ()
endif ()
diff --git a/Modules/Compiler/PGI-CXX.cmake b/Modules/Compiler/PGI-CXX.cmake
index 35076bb38..c77de3605 100644
--- a/Modules/Compiler/PGI-CXX.cmake
+++ b/Modules/Compiler/PGI-CXX.cmake
@@ -6,15 +6,19 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION -A)
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_CXX11_STANDARD_COMPILE_OPTION --c++11 -A)
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION --c++11 --gnu_extensions)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.7)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION --c++14 -A)
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION --c++14 --gnu_extensions)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.1)
set(CMAKE_CXX17_STANDARD_COMPILE_OPTION --c++17 -A)
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION --c++17 --gnu_extensions)
+ set(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT ON)
endif()
endif()
endif()
diff --git a/Modules/Compiler/SunPro-C.cmake b/Modules/Compiler/SunPro-C.cmake
index c4aba8eca..7e962b8ee 100644
--- a/Modules/Compiler/SunPro-C.cmake
+++ b/Modules/Compiler/SunPro-C.cmake
@@ -39,10 +39,13 @@ set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.13)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
elseif (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.11)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
diff --git a/Modules/Compiler/SunPro-CXX-FeatureTests.cmake b/Modules/Compiler/SunPro-CXX-FeatureTests.cmake
index 279d87538..e7133c153 100644
--- a/Modules/Compiler/SunPro-CXX-FeatureTests.cmake
+++ b/Modules/Compiler/SunPro-CXX-FeatureTests.cmake
@@ -6,6 +6,14 @@
set(_cmake_oldestSupported "__SUNPRO_CC >= 0x5130")
+set(SolarisStudio126_CXX14 "(__SUNPRO_CC >= 0x5150) && __cplusplus >= 201402L")
+set(_cmake_feature_test_cxx_aggregate_default_initializers "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_digit_separators "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_generic_lambdas "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_lambda_init_captures "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_return_type_deduction "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_variable_templates "${SolarisStudio126_CXX14}")
+
set(SolarisStudio126_CXX11 "(__SUNPRO_CC >= 0x5150) && __cplusplus >= 201103L")
set(_cmake_feature_test_cxx_decltype_auto "${SolarisStudio126_CXX11}")
diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake
index 5ce58b221..c946c6436 100644
--- a/Modules/Compiler/SunPro-CXX.cmake
+++ b/Modules/Compiler/SunPro-CXX.cmake
@@ -48,9 +48,15 @@ set(CMAKE_CXX_CREATE_STATIC_LIBRARY
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++03")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX_LINK_WITH_STANDARD_COMPILE_OPTION 1)
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.14)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=c++14")
+ endif()
else()
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-library=stlport4")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-library=stlport4")
diff --git a/Modules/Compiler/XL-C-DetermineCompiler.cmake b/Modules/Compiler/XL-C-DetermineCompiler.cmake
index 484811efe..3f4e05c55 100644
--- a/Modules/Compiler/XL-C-DetermineCompiler.cmake
+++ b/Modules/Compiler/XL-C-DetermineCompiler.cmake
@@ -1,4 +1,4 @@
-set(_compiler_id_pp_test "defined(__ibmxl__) || (defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800)")
+set(_compiler_id_pp_test "defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800")
include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-C-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-C.cmake b/Modules/Compiler/XL-C.cmake
index 5dc8bc17f..2077bdabd 100644
--- a/Modules/Compiler/XL-C.cmake
+++ b/Modules/Compiler/XL-C.cmake
@@ -6,36 +6,18 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
# -qthreaded = Ensures that all optimizations will be thread-safe
string(APPEND CMAKE_C_FLAGS_INIT " -qthreaded")
-# XL v13.1.1 for Linux ppc64 little-endian switched to using a clang based
-# front end and accepts the -std= option while only reserving -qlanglevel= for
-# compatibility. All other versions (previous versions on Linux ppc64
-# little-endian, all versions on Linux ppc64 big-endian, all versions on AIX
-# and BGQ, etc) are derived from the UNIX compiler and only accept the
-# -qlanglvl option.
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
- if (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND
- 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")
- set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
- set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
- if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
- set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
- set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
- else ()
- set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
- set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
- endif ()
- else ()
- set(CMAKE_C90_STANDARD_COMPILE_OPTION "-qlanglvl=stdc89")
- set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-qlanglvl=extc89")
- set(CMAKE_C99_STANDARD_COMPILE_OPTION "-qlanglvl=stdc99")
- set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-qlanglvl=extc99")
- if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1)
- set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
- set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
- endif ()
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-qlanglvl=stdc89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-qlanglvl=extc89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-qlanglvl=stdc99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-qlanglvl=extc99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
endif ()
endif()
-__compiler_check_default_language_standard(C 10.1 90)
+__compiler_check_default_language_standard(C 10.1 90 11.1 99)
diff --git a/Modules/Compiler/XL-CXX-DetermineCompiler.cmake b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
index 2bf1ec69c..dffa4bc21 100644
--- a/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
+++ b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
@@ -1,4 +1,4 @@
-set(_compiler_id_pp_test "defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800)")
+set(_compiler_id_pp_test "defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800")
include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-CXX-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-CXX.cmake b/Modules/Compiler/XL-CXX.cmake
index b87e9238b..303785112 100644
--- a/Modules/Compiler/XL-CXX.cmake
+++ b/Modules/Compiler/XL-CXX.cmake
@@ -6,41 +6,23 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
# -qthreaded = Ensures that all optimizations will be thread-safe
string(APPEND CMAKE_CXX_FLAGS_INIT " -qthreaded")
-# XL v13.1.1 for Linux ppc64 little-endian switched to using a clang based
-# front end and accepts the -std= option while only reserving -qlanglevel= for
-# compatibility. All other versions (previous versions on Linux ppc64
-# little-endian, all versions on Linux ppc64 big-endian, all versions on AIX
-# and BGQ, etc) are derived from the UNIX compiler and only accept the
-# -qlanglvl option.
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
- if (CMAKE_SYSTEM MATCHES "Linux.*ppc64")
- if (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND
- CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
- set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
- set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
- 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++1y")
- set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-qlanglvl=extended1y")
- else ()
- set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
- set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
- endif ()
- else ()
- # The non-clang based Linux ppc64 compiler, both big-endian and
- # little-endian lacks, the non-extension language level flags
- set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-qlanglvl=extended")
- set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-qlanglvl=extended")
- set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
- set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
- endif ()
- else ()
+ if(CMAKE_SYSTEM MATCHES "Linux")
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ else()
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-qlanglvl=strict98")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-qlanglvl=extended")
- set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
- set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
- endif ()
+ endif()
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.1.0)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-qlanglvl=extended1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-qlanglvl=extended1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
endif ()
__compiler_check_default_language_standard(CXX 10.1 98)
diff --git a/Modules/Compiler/XL.cmake b/Modules/Compiler/XL.cmake
index 68dc28a92..a9cec113f 100644
--- a/Modules/Compiler/XL.cmake
+++ b/Modules/Compiler/XL.cmake
@@ -10,12 +10,6 @@ set(__COMPILER_XL 1)
include(Compiler/CMakeCommonCompilerMacros)
-# Find the CreateExportList program that comes with this toolchain.
-find_program(CMAKE_XL_CreateExportList
- NAMES CreateExportList
- DOC "IBM XL CreateExportList tool"
- )
-
macro(__compiler_xl lang)
# Feature flags.
set(CMAKE_${lang}_VERBOSE_FLAG "-V")
@@ -35,20 +29,4 @@ macro(__compiler_xl lang)
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")
-
- # CMAKE_XL_CreateExportList is part of the AIX XL compilers but not the linux ones.
- # If we found the tool, we'll use it to create exports, otherwise stick with the regular
- # create shared library compile line.
- if (CMAKE_XL_CreateExportList)
- # The compiler front-end passes all object files, archive files, and shared
- # library files named on the command line to CreateExportList to create a
- # list of all symbols to be exported from the shared library. This causes
- # all archive members to be copied into the shared library whether they are
- # needed or not. Instead we run the tool ourselves to pass only the object
- # files so that we export only the symbols actually provided by the sources.
- set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
- "${CMAKE_XL_CreateExportList} <OBJECT_DIR>/objects.exp <OBJECTS>"
- "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
- )
- endif()
endmacro()
diff --git a/Modules/Compiler/XLClang-C-DetermineCompiler.cmake b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
new file mode 100644
index 000000000..4d899213a
--- /dev/null
+++ b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-C.cmake b/Modules/Compiler/XLClang-C.cmake
new file mode 100644
index 000000000..54c18a668
--- /dev/null
+++ b/Modules/Compiler/XLClang-C.cmake
@@ -0,0 +1,20 @@
+include(Compiler/XLClang)
+__compiler_xlclang(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")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif()
+
+__compiler_check_default_language_standard(C 13.1.1 99)
diff --git a/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
new file mode 100644
index 000000000..4d899213a
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-CXX.cmake b/Modules/Compiler/XLClang-CXX.cmake
new file mode 100644
index 000000000..9ea3d7cac
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX.cmake
@@ -0,0 +1,27 @@
+include(Compiler/XLClang)
+__compiler_xlclang(CXX)
+
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+ 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++1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.1.0)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ endif()
+endif()
+
+__compiler_check_default_language_standard(CXX 13.1.1 98)
+
+set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> -x c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Compiler/XLClang.cmake b/Modules/Compiler/XLClang.cmake
new file mode 100644
index 000000000..cdf0fdca1
--- /dev/null
+++ b/Modules/Compiler/XLClang.cmake
@@ -0,0 +1,22 @@
+# 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_XLCLANG)
+ return()
+endif()
+set(__COMPILER_XLCLANG 1)
+
+include(Compiler/XL)
+
+macro(__compiler_xlclang lang)
+ __compiler_xl(${lang})
+
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-V")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIC")
+ set(CMAKE_${lang}_RESPONSE_FILE_FLAG "@")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@")
+endmacro()
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 22e052334..20b37d222 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -202,23 +202,24 @@ External Project Definition
:command:`file(DOWNLOAD)`)
``NETRC <level>``
- 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)`)
+ 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)`)
Valid levels are:
``IGNORED``
- The .netrc file is ignored.
+ The ``.netrc`` file is ignored.
This is the default.
``OPTIONAL``
- The .netrc file is optional, and information in the URL is preferred.
- The file will be scanned to find which ever information is not specified
- in the URL.
+ The ``.netrc`` file is optional, and information in the URL
+ is preferred. The file will be scanned to find which ever
+ information is not specified in the URL.
``REQUIRED``
- The .netrc file is required, and information in the URL is ignored.
+ The ``.netrc`` file is required, and information in the URL
+ is ignored.
``NETRC_FILE <file>``
- Specify an alternative .netrc file to the one in your home directory
+ 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)`)
@@ -251,6 +252,9 @@ External Project Definition
The lack of such deterministic behavior makes the main project lose
traceability and repeatability.
+ If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with
+ branch names and tags. A commit hash is not allowed.
+
``GIT_REMOTE_NAME <name>``
The optional name of the remote. If this option is not specified, it
defaults to ``origin``.
@@ -418,6 +422,10 @@ 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 orginal projects settings for the GHS toolset and target system
+ customization cache variables are propagated into the external project.
+
``SOURCE_SUBDIR <dir>``
When no ``CONFIGURE_COMMAND`` option is specified, the configure step
assumes the external project has a ``CMakeLists.txt`` file at the top of
@@ -1053,11 +1061,6 @@ define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
)
function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
- if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
- set(git_clone_shallow_options "--depth 1 --no-single-branch")
- else()
- set(git_clone_shallow_options "--depth 1")
- endif()
if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
# Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
set(git_checkout_explicit-- "--")
@@ -1067,18 +1070,41 @@ function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git
# because that will not search for remote branch names, a common use case.
set(git_checkout_explicit-- "")
endif()
- file(WRITE ${script_filename}
-"if(\"${git_tag}\" STREQUAL \"\")
- message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
-endif()
+ if("${git_tag}" STREQUAL "")
+ message(FATAL_ERROR "Tag for git checkout should not be empty.")
+ endif()
-set(run 0)
+ set(git_clone_options)
+ if(git_shallow)
+ if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
+ list(APPEND git_clone_options "--depth 1 --no-single-branch")
+ else()
+ list(APPEND git_clone_options "--depth 1")
+ endif()
+ endif()
+ if(git_progress)
+ list(APPEND git_clone_options --progress)
+ endif()
+ foreach(config IN LISTS git_config)
+ list(APPEND git_clone_options --config ${config})
+ endforeach()
+ if(NOT ${git_remote_name} STREQUAL "origin")
+ list(APPEND git_clone_options --origin \"${git_remote_name}\")
+ endif()
-if(\"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
- set(run 1)
-endif()
+ string (REPLACE ";" " " git_clone_options "${git_clone_options}")
-if(NOT run)
+ set(git_options)
+ # disable cert checking if explicitly told not to do it
+ if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify)
+ set(git_options
+ -c http.sslVerify=false)
+ endif()
+ string (REPLACE ";" " " git_options "${git_options}")
+
+ file(WRITE ${script_filename}
+"
+if(NOT \"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
return()
endif()
@@ -1091,38 +1117,12 @@ if(error_code)
message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
endif()
-set(git_options)
-
-# disable cert checking if explicitly told not to do it
-set(tls_verify \"${tls_verify}\")
-if(NOT \"x${tls_verify}\" STREQUAL \"x\" AND NOT tls_verify)
- list(APPEND git_options
- -c http.sslVerify=false)
-endif()
-
-set(git_clone_options)
-
-set(git_shallow \"${git_shallow}\")
-if(git_shallow)
- list(APPEND git_clone_options ${git_clone_shallow_options})
-endif()
-
-set(git_progress \"${git_progress}\")
-if(git_progress)
- list(APPEND git_clone_options --progress)
-endif()
-
-set(git_config \"${git_config}\")
-foreach(config IN LISTS git_config)
- list(APPEND git_clone_options --config \${config})
-endforeach()
-
# try the clone 3 times in case there is an odd git clone issue
set(error_code 1)
set(number_of_tries 0)
while(error_code AND number_of_tries LESS 3)
execute_process(
- COMMAND \"${git_EXECUTABLE}\" \${git_options} clone \${git_clone_options} --origin \"${git_remote_name}\" \"${git_repository}\" \"${src_name}\"
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} clone ${git_clone_options} \"${git_repository}\" \"${src_name}\"
WORKING_DIRECTORY \"${work_dir}\"
RESULT_VARIABLE error_code
)
@@ -1137,7 +1137,7 @@ if(error_code)
endif()
execute_process(
- COMMAND \"${git_EXECUTABLE}\" \${git_options} checkout ${git_tag} ${git_checkout_explicit--}
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} checkout ${git_tag} ${git_checkout_explicit--}
WORKING_DIRECTORY \"${work_dir}/${src_name}\"
RESULT_VARIABLE error_code
)
@@ -1146,16 +1146,7 @@ if(error_code)
endif()
execute_process(
- COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule init ${git_submodules}
- WORKING_DIRECTORY \"${work_dir}/${src_name}\"
- RESULT_VARIABLE error_code
- )
-if(error_code)
- message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
-endif()
-
-execute_process(
- COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule update --recursive --init ${git_submodules}
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update --recursive --init ${git_submodules}
WORKING_DIRECTORY \"${work_dir}/${src_name}\"
RESULT_VARIABLE error_code
)
@@ -1169,7 +1160,6 @@ execute_process(
COMMAND \${CMAKE_COMMAND} -E copy
\"${gitclone_infofile}\"
\"${gitclone_stampfile}\"
- WORKING_DIRECTORY \"${work_dir}/${src_name}\"
RESULT_VARIABLE error_code
)
if(error_code)
@@ -1182,18 +1172,12 @@ endif()
endfunction()
function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
+ if("${hg_tag}" STREQUAL "")
+ message(FATAL_ERROR "Tag for hg checkout should not be empty.")
+ endif()
file(WRITE ${script_filename}
-"if(\"${hg_tag}\" STREQUAL \"\")
- message(FATAL_ERROR \"Tag for hg checkout should not be empty.\")
-endif()
-
-set(run 0)
-
-if(\"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
- set(run 1)
-endif()
-
-if(NOT run)
+"
+if(NOT \"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
return()
endif()
@@ -1230,7 +1214,6 @@ execute_process(
COMMAND \${CMAKE_COMMAND} -E copy
\"${hgclone_infofile}\"
\"${hgclone_stampfile}\"
- WORKING_DIRECTORY \"${work_dir}/${src_name}\"
RESULT_VARIABLE error_code
)
if(error_code)
@@ -1244,16 +1227,16 @@ endfunction()
function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name git_submodules git_repository work_dir)
+ 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)
endif()
file(WRITE ${script_filename}
-"if(\"${git_tag}\" STREQUAL \"\")
- message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
-endif()
-
+"
execute_process(
COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 HEAD
WORKING_DIRECTORY \"${work_dir}\"
@@ -2460,7 +2443,7 @@ function(_ep_add_download_command name)
#
set(repository ${git_repository})
set(module)
- set(tag)
+ set(tag ${git_remote_name})
configure_file(
"${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
"${stamp_dir}/${name}-gitinfo.txt"
@@ -2871,18 +2854,6 @@ function(_ep_extract_configure_command var name)
set(has_cmake_cache_default_args 1)
endif()
- if(has_cmake_cache_args OR has_cmake_cache_default_args)
- set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
- if(has_cmake_cache_args)
- _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
- endif()
- if(has_cmake_cache_default_args)
- _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
- endif()
- _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
- list(APPEND cmd "-C${_ep_cache_args_script}")
- endif()
-
get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
get_target_property(cmake_generator_instance ${name} _EP_CMAKE_GENERATOR_INSTANCE)
get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
@@ -2903,6 +2874,16 @@ function(_ep_extract_configure_command var name)
list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
else()
list(APPEND cmd "-G${CMAKE_GENERATOR}")
+ if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ set(has_cmake_cache_default_args 1)
+ set(cmake_cache_default_args ${cmake_cache_default_args}
+ "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
+ "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
+ "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
+ "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
+ "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
+ "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}")
+ endif()
endif()
if(cmake_generator_platform)
message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
@@ -2924,6 +2905,18 @@ function(_ep_extract_configure_command var name)
endif()
endif()
+ if(has_cmake_cache_args OR has_cmake_cache_default_args)
+ set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
+ if(has_cmake_cache_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
+ endif()
+ if(has_cmake_cache_default_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
+ endif()
+ _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
+ list(APPEND cmd "-C${_ep_cache_args_script}")
+ endif()
+
list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
endif()
diff --git a/Modules/FindALSA.cmake b/Modules/FindALSA.cmake
index f27d7fe97..88e2681eb 100644
--- a/Modules/FindALSA.cmake
+++ b/Modules/FindALSA.cmake
@@ -5,9 +5,9 @@
FindALSA
--------
-Find alsa
+Find Advanced Linux Sound Architecture (ALSA)
-Find the alsa libraries (asound)
+Find the alsa libraries (``asound``)
IMPORTED Targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindAVIFile.cmake b/Modules/FindAVIFile.cmake
index c12512f15..96554405d 100644
--- a/Modules/FindAVIFile.cmake
+++ b/Modules/FindAVIFile.cmake
@@ -7,7 +7,7 @@ FindAVIFile
Locate AVIFILE library and include paths
-AVIFILE (http://avifile.sourceforge.net/)is a set of libraries for
+AVIFILE (http://avifile.sourceforge.net/) is a set of libraries for
i386 machines to use various AVI codecs. Support is limited beyond
Linux. Windows provides native AVI support, and so doesn't need this
library. This module defines
diff --git a/Modules/FindArmadillo.cmake b/Modules/FindArmadillo.cmake
index ce76c99df..c4e55ce57 100644
--- a/Modules/FindArmadillo.cmake
+++ b/Modules/FindArmadillo.cmake
@@ -5,9 +5,8 @@
FindArmadillo
-------------
-Find Armadillo
-
-Find the Armadillo C++ library
+Find the Armadillo C++ library.
+Armadillo is library for linear algebra & scientific computing.
Using Armadillo:
diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake
index c6c8de0d5..6b5828eef 100644
--- a/Modules/FindBISON.cmake
+++ b/Modules/FindBISON.cmake
@@ -16,10 +16,10 @@ The module defines the following variables:
version of ``bison``
``BISON_FOUND``
- true if the program was found
+ "True" if the program was found
The minimum required version of ``bison`` can be specified using the
-standard CMake syntax, e.g. ``find_package(BISON 2.1.3)``.
+standard CMake syntax, e.g. :command:`find_package(BISON 2.1.3)`.
If ``bison`` is found, the module defines the macro::
@@ -55,7 +55,7 @@ The options are:
The macro defines the following variables:
``BISON_<Name>_DEFINED``
- true is the macro ran successfully
+ ``True`` is the macro ran successfully
``BISON_<Name>_INPUT``
The input source file, an alias for <YaccInput>
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index 0aa4f5035..77f9d0e40 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -5,12 +5,12 @@
FindBLAS
--------
-Find BLAS library
+Find Basic Linear Algebra Subprograms (BLAS) library
-This module finds an installed fortran library that implements the
+This module finds an installed Fortran library that implements the
BLAS linear-algebra interface (see http://www.netlib.org/blas/). The
-list of libraries searched for is taken from the autoconf macro file,
-acx_blas.m4 (distributed at
+list of libraries searched for is taken from the ``autoconf`` macro file,
+``acx_blas.m4`` (distributed at
http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
Input Variables
@@ -52,7 +52,7 @@ The following variables may be set to influence this module's behavior:
if ``ON`` tries to find the BLAS95 interfaces
``BLA_PREFER_PKGCONFIG``
- if set pkg-config will be used to search for a BLAS library first
+ if set ``pkg-config`` will be used to search for a BLAS library first
and if one is found that is preferred
Result Variables
@@ -63,7 +63,7 @@ This module defines the following variables:
``BLAS_FOUND``
library implementing the BLAS interface is found
``BLAS_LINKER_FLAGS``
- uncached list of required linker flags (excluding -l and -L).
+ uncached list of required linker flags (excluding ``-l`` and ``-L``).
``BLAS_LIBRARIES``
uncached list of libraries (using full path name) to link against
to use BLAS (may be empty if compiler implicitly links BLAS)
@@ -75,7 +75,7 @@ This module defines the following variables:
.. note::
- C or CXX must be enabled to use Intel MKL
+ C or CXX must be enabled to use Intel Math Kernel Library (MKL)
For example, to use Intel MKL libraries and/or Intel compiler:
@@ -83,6 +83,13 @@ This module defines the following variables:
set(BLA_VENDOR Intel10_64lp)
find_package(BLAS)
+
+Hints
+^^^^^
+
+Set ``MKLROOT`` environment variable to a directory that contains an MKL
+installation.
+
#]=======================================================================]
include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
@@ -145,7 +152,9 @@ macro(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list _thread)
foreach(_library ${_list})
set(_combined_name ${_combined_name}_${_library})
-
+ if(NOT "${_thread}" STREQUAL "")
+ set(_combined_name ${_combined_name}_thread)
+ endif()
if(_libraries_work)
if (BLA_STATIC)
if (WIN32)
@@ -232,7 +241,8 @@ if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
set(BLAS_mkl_DLL_SUFFIX "_dll")
endif()
else()
- if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+ # Switch to GNU Fortran support layer if needed (but not on Apple, where MKL does not provide it)
+ if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
set(BLAS_mkl_INTFACE "gf")
set(BLAS_mkl_THREADING "gnu")
set(BLAS_mkl_OMP "gomp")
@@ -394,6 +404,23 @@ if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
endif ()
endif ()
+ if (DEFINED ENV{MKLROOT})
+ if (BLA_VENDOR STREQUAL "Intel10_32")
+ set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/ia32")
+ elseif (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$")
+ set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/intel64")
+ endif ()
+ endif ()
+ if (_BLAS_MKLROOT_LIB_DIR)
+ if (WIN32)
+ string(APPEND _BLAS_MKLROOT_LIB_DIR "_win")
+ elseif (APPLE)
+ string(APPEND _BLAS_MKLROOT_LIB_DIR "_mac")
+ else ()
+ string(APPEND _BLAS_MKLROOT_LIB_DIR "_lin")
+ endif ()
+ endif ()
+
foreach (IT ${BLAS_SEARCH_LIBS})
string(REPLACE " " ";" SEARCH_LIBS ${IT})
if (NOT ${_LIBRARIES})
@@ -404,6 +431,7 @@ if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
""
"${SEARCH_LIBS}"
"${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
+ "${_BLAS_MKLROOT_LIB_DIR}"
)
endif ()
endforeach ()
@@ -453,6 +481,18 @@ if (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
""
)
endif()
+ if(NOT BLAS_LIBRARIES)
+ find_package(Threads)
+ # OpenBLAS (http://www.openblas.net)
+ check_fortran_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "openblas"
+ "${CMAKE_THREAD_LIBS_INIT}"
+ )
+ endif()
endif ()
if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
diff --git a/Modules/FindBZip2.cmake b/Modules/FindBZip2.cmake
index 249514864..309b97145 100644
--- a/Modules/FindBZip2.cmake
+++ b/Modules/FindBZip2.cmake
@@ -65,40 +65,40 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(BZip2
VERSION_VAR BZIP2_VERSION_STRING)
if (BZIP2_FOUND)
- set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})
- include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)
- include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
- cmake_push_check_state()
- set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY})
- set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR})
- set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES})
- CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit "bzlib.h" BZIP2_NEED_PREFIX)
- cmake_pop_check_state()
-
- if(NOT TARGET BZip2::BZip2)
- add_library(BZip2::BZip2 UNKNOWN IMPORTED)
+ set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY})
+ set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES})
+ CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit "bzlib.h" BZIP2_NEED_PREFIX)
+ cmake_pop_check_state()
+
+ if(NOT TARGET BZip2::BZip2)
+ add_library(BZip2::BZip2 UNKNOWN IMPORTED)
+ set_target_properties(BZip2::BZip2 PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${BZIP2_INCLUDE_DIRS}")
+
+ if(BZIP2_LIBRARY_RELEASE)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(BZip2::BZip2 PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${BZIP2_INCLUDE_DIRS}")
-
- if(BZIP2_LIBRARY_RELEASE)
- set_property(TARGET BZip2::BZip2 APPEND PROPERTY
- IMPORTED_CONFIGURATIONS RELEASE)
- set_target_properties(BZip2::BZip2 PROPERTIES
- IMPORTED_LOCATION_RELEASE "${BZIP2_LIBRARY_RELEASE}")
- endif()
-
- if(BZIP2_LIBRARY_DEBUG)
- set_property(TARGET BZip2::BZip2 APPEND PROPERTY
- IMPORTED_CONFIGURATIONS DEBUG)
- set_target_properties(BZip2::BZip2 PROPERTIES
- IMPORTED_LOCATION_DEBUG "${BZIP2_LIBRARY_DEBUG}")
- endif()
-
- if(NOT BZIP2_LIBRARY_RELEASE AND NOT BZIP2_LIBRARY_DEBUG)
- set_property(TARGET BZip2::BZip2 APPEND PROPERTY
- IMPORTED_LOCATION "${BZIP2_LIBRARY}")
- endif()
+ IMPORTED_LOCATION_RELEASE "${BZIP2_LIBRARY_RELEASE}")
endif()
+
+ if(BZIP2_LIBRARY_DEBUG)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(BZip2::BZip2 PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${BZIP2_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT BZIP2_LIBRARY_RELEASE AND NOT BZIP2_LIBRARY_DEBUG)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_LOCATION "${BZIP2_LIBRARY}")
+ endif()
+ endif()
endif ()
mark_as_advanced(BZIP2_INCLUDE_DIR)
diff --git a/Modules/FindBacktrace.cmake b/Modules/FindBacktrace.cmake
index e1f45f7d4..cf1632a57 100644
--- a/Modules/FindBacktrace.cmake
+++ b/Modules/FindBacktrace.cmake
@@ -5,30 +5,30 @@
FindBacktrace
-------------
-Find provider for backtrace(3).
+Find provider for `backtrace(3) <http://man7.org/linux/man-pages/man3/backtrace.3.html>`__.
-Checks if OS supports backtrace(3) via either libc or custom library.
+Checks if OS supports ``backtrace(3)`` via either ``libc`` or custom library.
This module defines the following variables:
``Backtrace_HEADER``
- The header file needed for backtrace(3). Cached.
+ The header file needed for ``backtrace(3)``. Cached.
Could be forcibly set by user.
``Backtrace_INCLUDE_DIRS``
- The include directories needed to use backtrace(3) header.
+ The include directories needed to use ``backtrace(3)`` header.
``Backtrace_LIBRARIES``
- The libraries (linker flags) needed to use backtrace(3), if any.
+ The libraries (linker flags) needed to use ``backtrace(3)``, if any.
``Backtrace_FOUND``
- Is set if and only if backtrace(3) support detected.
+ Is set if and only if ``backtrace(3)`` support detected.
The following cache variables are also available to set or use:
``Backtrace_LIBRARY``
The external library providing backtrace, if any.
``Backtrace_INCLUDE_DIR``
- The directory holding the backtrace(3) header.
+ The directory holding the ``backtrace(3)`` header.
-Typical usage is to generate of header file using configure_file() with the
-contents like the following::
+Typical usage is to generate of header file using :command:`configure_file`
+with the contents like the following::
#cmakedefine01 Backtrace_FOUND
#if Backtrace_FOUND
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 6a59dffc8..25dd397cf 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -30,12 +30,18 @@ case results are reported in variables::
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 - BOOST_VERSION value from boost/version.hpp
- Boost_LIB_VERSION - Version string appended to library filenames
- Boost_MAJOR_VERSION - Boost major version number (X in X.y.z)
- Boost_MINOR_VERSION - Boost minor version number (Y in x.Y.z)
- Boost_SUBMINOR_VERSION - Boost subminor version number (Z in x.y.Z)
+ 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
@@ -72,8 +78,9 @@ and saves search results persistently in CMake cache entries::
The following :prop_tgt:`IMPORTED` targets are also defined::
- Boost::boost - Target for header-only dependencies
+ 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
@@ -85,33 +92,33 @@ The following :prop_tgt:`IMPORTED` targets are also defined::
Boost::dynamic_linking - interface target to enable dynamic linking
linking with MSVC (adds BOOST_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 find_package and if
-Boost::system is not added to target_link_libraries. If using
-Boost::thread, then Threads::Threads will also be added automatically.
+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
-find_package(Boost) in the same directory or sub-directories with
+: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.
-Users may set these hints or results as cache entries. Projects
+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
not specified as CMake variables or cache entries.
-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
-Boost_ADDITIONAL_VERSIONS), "lib" directories near Boost_INCLUDE_DIR,
+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
+``Boost_ADDITIONAL_VERSIONS``), "lib" directories near ``Boost_INCLUDE_DIR``,
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.
+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``.
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.
@@ -162,10 +169,6 @@ 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_DETAILED_FAILURE_MSG
- - Set to ON to add detailed information to the
- failure message even when the REQUIRED option
- is not given to the find_package call.
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
@@ -179,9 +182,9 @@ Other variables one may set to control this module are::
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
+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::
add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
@@ -227,24 +230,177 @@ Example to find Boost headers and some *static* (release only) libraries::
Boost CMake
^^^^^^^^^^^
-If Boost was built using the boost-cmake project 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
+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
and this module returns with no further action. See documentation of
the Boost CMake package configuration for details on what it provides.
-Set Boost_NO_BOOST_CMAKE to ON to disable the search for boost-cmake.
+Set ``Boost_NO_BOOST_CMAKE`` to ``ON``, to disable the search for boost-cmake.
#]=======================================================================]
+# The FPHSA helper provides standard way of reporting final search results to
+# the user including the version and component checks.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
# Save project's policies
cmake_policy(PUSH)
cmake_policy(SET CMP0057 NEW) # if IN_LIST
+function(_boost_get_existing_target component target_var)
+ set(names "${component}")
+ if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9])?$")
+ # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc.
+ list(APPEND names
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}" # python
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}" # pythonX
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}${CMAKE_MATCH_4}" #pythonXY
+ )
+ endif()
+ # https://github.com/boost-cmake/boost-cmake uses boost::file_system etc.
+ # So handle similar constructions of target names
+ string(TOLOWER "${component}" lower_component)
+ list(APPEND names "${lower_component}")
+ foreach(prefix Boost boost)
+ foreach(name IN LISTS names)
+ if(TARGET "${prefix}::${name}")
+ set(${target_var} "${prefix}::${name}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ endforeach()
+ set(${target_var} "" PARENT_SCOPE)
+endfunction()
+
+function(_boost_get_canonical_target_name component target_var)
+ string(TOLOWER "${component}" component)
+ if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9])?$")
+ # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc.
+ set(${target_var} "Boost::${CMAKE_MATCH_1}${CMAKE_MATCH_2}" PARENT_SCOPE)
+ else()
+ set(${target_var} "Boost::${component}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(_boost_set_in_parent_scope name value)
+ # Set a variable in parent scope and make it visibile in current scope
+ set(${name} "${value}" PARENT_SCOPE)
+ set(${name} "${value}")
+endmacro()
+
+macro(_boost_set_if_unset name value)
+ if(NOT ${name})
+ _boost_set_in_parent_scope(${name} "${value}")
+ endif()
+endmacro()
+
+macro(_boost_set_cache_if_unset name value)
+ if(NOT ${name})
+ set(${name} "${value}" CACHE STRING "" FORCE)
+ endif()
+endmacro()
+
+macro(_boost_append_include_dir target)
+ get_target_property(inc "${target}" INTERFACE_INCLUDE_DIRECTORIES)
+ if(inc)
+ list(APPEND include_dirs "${inc}")
+ endif()
+endmacro()
+
+function(_boost_set_legacy_variables_from_config)
+ # Set legacy variables for compatibility if not set
+ set(include_dirs "")
+ set(library_dirs "")
+ set(libraries "")
+ # Header targets Boost::headers or Boost::boost
+ foreach(comp headers boost)
+ _boost_get_existing_target(${comp} target)
+ if(target)
+ _boost_append_include_dir("${target}")
+ endif()
+ endforeach()
+ # Library targets
+ foreach(comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${comp} uppercomp)
+ # Overwrite if set
+ _boost_set_in_parent_scope(Boost_${uppercomp}_FOUND "${Boost_${comp}_FOUND}")
+ if(Boost_${comp}_FOUND)
+ _boost_get_existing_target(${comp} target)
+ if(NOT target)
+ if(Boost_DEBUG OR Boost_VERBOSE)
+ message(WARNING "Could not find imported target for required component '${comp}'. Standard variables for this component might be missing. Refer to the documentation of your Boost installation for help on variables to use.")
+ endif()
+ continue()
+ endif()
+ _boost_append_include_dir("${target}")
+ _boost_set_if_unset(Boost_${uppercomp}_LIBRARY "${target}")
+ _boost_set_if_unset(Boost_${uppercomp}_LIBRARIES "${target}") # Very old legacy variable
+ list(APPEND libraries "${target}")
+ foreach(cfg RELEASE DEBUG)
+ get_target_property(lib ${target} IMPORTED_LOCATION_${cfg})
+ if(lib)
+ get_filename_component(lib_dir "${lib}" DIRECTORY)
+ list(APPEND library_dirs ${lib_dir})
+ _boost_set_cache_if_unset(Boost_${uppercomp}_LIBRARY_${cfg} "${lib}")
+ endif()
+ endforeach()
+ _boost_get_canonical_target_name("${comp}" canonical_target)
+ if(NOT TARGET "${canonical_target}")
+ add_library("${canonical_target}" INTERFACE IMPORTED)
+ target_link_libraries("${canonical_target}" INTERFACE "${target}")
+ endif()
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES include_dirs)
+ list(REMOVE_DUPLICATES library_dirs)
+ _boost_set_if_unset(Boost_INCLUDE_DIRS "${include_dirs}")
+ _boost_set_if_unset(Boost_LIBRARY_DIRS "${library_dirs}")
+ _boost_set_if_unset(Boost_LIBRARIES "${libraries}")
+ _boost_set_if_unset(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}")
+ find_path(Boost_INCLUDE_DIR
+ NAMES boost/version.hpp boost/config.hpp
+ HINTS ${Boost_INCLUDE_DIRS}
+ NO_DEFAULT_PATH
+ )
+ if(NOT Boost_VERSION_MACRO OR NOT Boost_LIB_VERSION)
+ set(version_file ${Boost_INCLUDE_DIR}/boost/version.hpp)
+ if(EXISTS "${version_file}")
+ file(STRINGS "${version_file}" contents REGEX "#define BOOST_(LIB_)?VERSION ")
+ if(contents MATCHES "#define BOOST_VERSION ([0-9]+)")
+ _boost_set_if_unset(Boost_VERSION_MACRO "${CMAKE_MATCH_1}")
+ endif()
+ if(contents MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"")
+ _boost_set_if_unset(Boost_LIB_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ endif()
+ _boost_set_if_unset(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR})
+ _boost_set_if_unset(Boost_MINOR_VERSION ${Boost_VERSION_MINOR})
+ _boost_set_if_unset(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH})
+ if(WIN32)
+ _boost_set_if_unset(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
+ endif()
+ if(NOT TARGET Boost::headers)
+ add_library(Boost::headers INTERFACE IMPORTED)
+ target_include_directories(Boost::headers INTERFACE ${Boost_INCLUDE_DIRS})
+ endif()
+ # Legacy targets w/o functionality as all handled by defined targets
+ foreach(lib diagnostic_definitions disable_autolinking dynamic_linking)
+ if(NOT TARGET Boost::${lib})
+ add_library(Boost::${lib} INTERFACE IMPORTED)
+ endif()
+ endforeach()
+ if(NOT TARGET Boost::boost)
+ add_library(Boost::boost INTERFACE IMPORTED)
+ target_link_libraries(Boost::boost INTERFACE Boost::headers)
+ endif()
+endfunction()
+
#-------------------------------------------------------------------------------
-# Before we go searching, check whether boost-cmake is available, unless the
-# user specifically asked NOT to search for boost-cmake.
+# Before we go searching, check whether a boost cmake package is available, unless
+# the user specifically asked NOT to search for one.
#
# If Boost_DIR is set, this behaves as any find_package call would. If not,
# it looks at BOOST_ROOT and BOOSTROOT to find Boost.
@@ -266,13 +422,28 @@ if (NOT Boost_NO_BOOST_CMAKE)
find_package(Boost QUIET NO_MODULE)
mark_as_advanced(Boost_DIR)
- # If we found boost-cmake, then we're done. Print out what we found.
+ # If we found a boost cmake package, then we're done. Print out what we found.
# Otherwise let the rest of the module try to find it.
- if (Boost_FOUND)
- message(STATUS "Boost ${Boost_FIND_VERSION} found.")
- if (Boost_FIND_COMPONENTS)
- message(STATUS "Found Boost components:\n ${Boost_FIND_COMPONENTS}")
+ if(Boost_FOUND)
+ # Convert component found variables to standard variables if required
+ # Necessary for legacy boost-cmake and 1.70 builtin BoostConfig
+ if(Boost_FIND_COMPONENTS)
+ foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ if(DEFINED Boost_${_comp}_FOUND)
+ continue()
+ endif()
+ string(TOUPPER ${_comp} _uppercomp)
+ if(DEFINED Boost${_comp}_FOUND) # legacy boost-cmake project
+ set(Boost_${_comp}_FOUND ${Boost${_comp}_FOUND})
+ elseif(DEFINED Boost_${_uppercomp}_FOUND) # Boost 1.70
+ set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND})
+ endif()
+ endforeach()
endif()
+
+ find_package_handle_standard_args(Boost HANDLE_COMPONENTS CONFIG_MODE)
+ _boost_set_legacy_variables_from_config()
+
# Restore project's policies
cmake_policy(POP)
return()
@@ -284,6 +455,56 @@ endif()
# FindBoost functions & macros
#
+#
+# Print debug text if Boost_DEBUG is set.
+# Call example:
+# _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message")
+#
+function(_Boost_DEBUG_PRINT file line text)
+ if(Boost_DEBUG)
+ message(STATUS "[ ${file}:${line} ] ${text}")
+ endif()
+endfunction()
+
+#
+# _Boost_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT]
+# [SOURCE "short explanation of origin of var value"])
+#
+# ENVIRONMENT - look up environment variable instead of CMake variable
+#
+# Print variable name and its value if Boost_DEBUG is set.
+# Call example:
+# _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" BOOST_ROOT)
+#
+function(_Boost_DEBUG_PRINT_VAR file line name)
+ if(Boost_DEBUG)
+ cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN})
+
+ unset(source)
+ if(_args_SOURCE)
+ set(source " (${_args_SOURCE})")
+ endif()
+
+ if(_args_ENVIRONMENT)
+ if(DEFINED ENV{${name}})
+ set(value "\"$ENV{${name}}\"")
+ else()
+ set(value "<unset>")
+ endif()
+ set(_name "ENV{${name}}")
+ else()
+ if(DEFINED "${name}")
+ set(value "\"${${name}}\"")
+ else()
+ set(value "<unset>")
+ endif()
+ set(_name "${name}")
+ endif()
+
+ _Boost_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}")
+ endif()
+endfunction()
+
############################################
#
# Check the existence of the libraries.
@@ -401,11 +622,10 @@ macro(_Boost_FIND_LIBRARY var build_type)
# If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there.
if(Boost_LIBRARY_DIR_${build_type})
set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " Boost_LIBRARY_DIR_${build_type} = ${Boost_LIBRARY_DIR_${build_type}}"
- " _boost_LIBRARY_SEARCH_DIRS_${build_type} = ${_boost_LIBRARY_SEARCH_DIRS_${build_type}}")
- endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Boost_LIBRARY_DIR_${build_type}")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_LIBRARY_SEARCH_DIRS_${build_type}")
endif()
endmacro()
@@ -465,7 +685,7 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
endif()
elseif (GHSMULTI)
set(_boost_COMPILER "-ghs")
- elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
+ elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150)
# Not yet known.
set(_boost_COMPILER "")
@@ -486,6 +706,12 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
else() # VS 6.0 Good luck!
set(_boost_COMPILER "-vc6") # yes, this is correct
endif()
+
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
+ string(REPLACE "." ";" VERSION_LIST "${CMAKE_CXX_COMPILER_VERSION}")
+ list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR)
+ set(_boost_COMPILER "-clangw${CLANG_VERSION_MAJOR};${_boost_COMPILER}")
+ endif()
elseif (BORLAND)
set(_boost_COMPILER "-bcb")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
@@ -493,7 +719,7 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL")
set(_boost_COMPILER "-xlc")
elseif (MINGW)
- if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34)
+ if(Boost_VERSION_STRING VERSION_LESS 1.34)
set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34
else()
_Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR)
@@ -501,7 +727,7 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
endif()
elseif (UNIX)
_Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR)
- if(NOT Boost_VERSION VERSION_LESS 106900)
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0)
# From GCC 5 and clang 4, versioning changes and minor becomes patch.
# For those compilers, patch is exclude from compiler tag in Boost 1.69+ library naming.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 4)
@@ -512,25 +738,19 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34)
+ if(Boost_VERSION_STRING VERSION_LESS 1.34)
set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34
else()
# Determine which version of GCC we have.
if(APPLE)
- if(Boost_MINOR_VERSION)
- if(${Boost_MINOR_VERSION} GREATER 35)
- # In Boost 1.36.0 and newer, the mangled compiler name used
- # on macOS/Darwin is "xgcc".
- set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}")
- else()
- # In Boost <= 1.35.0, there is no mangled compiler name for
- # the macOS/Darwin version of GCC.
- set(_boost_COMPILER "")
- endif()
- else()
- # We don't know the Boost version, so assume it's
- # pre-1.36.0.
+ if(Boost_VERSION_STRING VERSION_LESS 1.36.0)
+ # In Boost <= 1.35.0, there is no mangled compiler name for
+ # the macOS/Darwin version of GCC.
set(_boost_COMPILER "")
+ else()
+ # In Boost 1.36.0 and newer, the mangled compiler name used
+ # on macOS/Darwin is "xgcc".
+ set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}")
endif()
else()
set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}")
@@ -541,9 +761,10 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
set(_boost_COMPILER "-clang${_boost_COMPILER_VERSION}")
endif()
else()
- # TODO at least Boost_DEBUG here?
set(_boost_COMPILER "")
endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_COMPILER" SOURCE "guessed")
set(${_ret} ${_boost_COMPILER} PARENT_SCOPE)
endfunction()
@@ -581,15 +802,14 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
# - Indent
# s;^set(; set(;;
# - Add conditionals
- # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION VERSION_LESS \10\20\3 AND Boost_VERSION VERSION_LESS xxxx);
+ # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION_STRING VERSION_LESS \1\.\2\.\3 AND Boost_VERSION_STRING VERSION_LESS xxxx);
#
# This results in the logic seen below, but will require the xxxx
# replacing with the following Boost release version (or the next
# minor version to be released, e.g. 1.59 was the latest at the time
- # of writing, making 1.60 the next, so 106000 is the needed version
- # number). Identical consecutive releases were then merged together
- # by updating the end range of the first block and removing the
- # following redundant blocks.
+ # of writing, making 1.60 the next. Identical consecutive releases
+ # were then merged together by updating the end range of the first
+ # block and removing the following redundant blocks.
#
# Running the script against all historical releases should be
# required only if the BoostScanDeps.cmake script logic is changed.
@@ -603,22 +823,22 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
endif()
set(_Boost_IMPORTED_TARGETS TRUE)
- if(Boost_VERSION AND Boost_VERSION VERSION_LESS 103300)
- message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION} (all versions older than 1.33)")
+ if(Boost_VERSION_STRING AND Boost_VERSION_STRING VERSION_LESS 1.33.0)
+ message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION_STRING} (all versions older than 1.33)")
set(_Boost_IMPORTED_TARGETS FALSE)
- elseif(NOT Boost_VERSION VERSION_LESS 103300 AND Boost_VERSION VERSION_LESS 103500)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.33.0 AND Boost_VERSION_STRING VERSION_LESS 1.35.0)
set(_Boost_IOSTREAMS_DEPENDENCIES regex thread)
set(_Boost_REGEX_DEPENDENCIES thread)
set(_Boost_WAVE_DEPENDENCIES filesystem thread)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 103500 AND Boost_VERSION VERSION_LESS 103600)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.35.0 AND Boost_VERSION_STRING VERSION_LESS 1.36.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MPI_DEPENDENCIES serialization)
set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 103600 AND Boost_VERSION VERSION_LESS 103800)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.36.0 AND Boost_VERSION_STRING VERSION_LESS 1.38.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
@@ -626,7 +846,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 103800 AND Boost_VERSION VERSION_LESS 104300)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.38.0 AND Boost_VERSION_STRING VERSION_LESS 1.43.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
@@ -635,7 +855,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES date_time)
set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 104300 AND Boost_VERSION VERSION_LESS 104400)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.43.0 AND Boost_VERSION_STRING VERSION_LESS 1.44.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
@@ -644,7 +864,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES date_time)
set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 104400 AND Boost_VERSION VERSION_LESS 104500)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.44.0 AND Boost_VERSION_STRING VERSION_LESS 1.45.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization)
@@ -653,7 +873,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES date_time)
set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 104500 AND Boost_VERSION VERSION_LESS 104700)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.45.0 AND Boost_VERSION_STRING VERSION_LESS 1.47.0)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
@@ -662,7 +882,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES date_time)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 104700 AND Boost_VERSION VERSION_LESS 104800)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.47.0 AND Boost_VERSION_STRING VERSION_LESS 1.48.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
@@ -672,7 +892,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES date_time)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 104800 AND Boost_VERSION VERSION_LESS 105000)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.48.0 AND Boost_VERSION_STRING VERSION_LESS 1.50.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
@@ -683,7 +903,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105000 AND Boost_VERSION VERSION_LESS 105300)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.50.0 AND Boost_VERSION_STRING VERSION_LESS 1.53.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
set(_Boost_IOSTREAMS_DEPENDENCIES regex)
@@ -694,7 +914,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105300 AND Boost_VERSION VERSION_LESS 105400)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.53.0 AND Boost_VERSION_STRING VERSION_LESS 1.54.0)
set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -706,7 +926,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105400 AND Boost_VERSION VERSION_LESS 105500)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.54.0 AND Boost_VERSION_STRING VERSION_LESS 1.55.0)
set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -719,7 +939,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105500 AND Boost_VERSION VERSION_LESS 105600)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.55.0 AND Boost_VERSION_STRING VERSION_LESS 1.56.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_COROUTINE_DEPENDENCIES context system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -732,7 +952,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105600 AND Boost_VERSION VERSION_LESS 105900)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.56.0 AND Boost_VERSION_STRING VERSION_LESS 1.59.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_COROUTINE_DEPENDENCIES context system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -746,7 +966,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 105900 AND Boost_VERSION VERSION_LESS 106000)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.59.0 AND Boost_VERSION_STRING VERSION_LESS 1.60.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_COROUTINE_DEPENDENCIES context system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -760,7 +980,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106000 AND Boost_VERSION VERSION_LESS 106100)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.60.0 AND Boost_VERSION_STRING VERSION_LESS 1.61.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_COROUTINE_DEPENDENCIES context system)
set(_Boost_FILESYSTEM_DEPENDENCIES system)
@@ -774,7 +994,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106100 AND Boost_VERSION VERSION_LESS 106200)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.61.0 AND Boost_VERSION_STRING VERSION_LESS 1.62.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_COROUTINE_DEPENDENCIES context system)
@@ -788,7 +1008,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106300)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0 AND Boost_VERSION_STRING VERSION_LESS 1.63.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_COROUTINE_DEPENDENCIES context system)
@@ -803,7 +1023,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106300 AND Boost_VERSION VERSION_LESS 106500)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.63.0 AND Boost_VERSION_STRING VERSION_LESS 1.65.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_COROUTINE_DEPENDENCIES context system)
@@ -819,7 +1039,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106500 AND Boost_VERSION VERSION_LESS 106700)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.65.0 AND Boost_VERSION_STRING VERSION_LESS 1.67.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_COROUTINE_DEPENDENCIES context system)
@@ -836,7 +1056,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106700 AND Boost_VERSION VERSION_LESS 106800)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.67.0 AND Boost_VERSION_STRING VERSION_LESS 1.68.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_COROUTINE_DEPENDENCIES context system)
@@ -853,7 +1073,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106800 AND Boost_VERSION VERSION_LESS 106900)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.68.0 AND Boost_VERSION_STRING VERSION_LESS 1.69.0)
set(_Boost_CHRONO_DEPENDENCIES system)
set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
set(_Boost_CONTRACT_DEPENDENCIES thread chrono system date_time)
@@ -871,7 +1091,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_TIMER_DEPENDENCIES chrono system)
set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
- elseif(NOT Boost_VERSION VERSION_LESS 106900 AND Boost_VERSION VERSION_LESS 107000)
+ elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0 AND Boost_VERSION_STRING VERSION_LESS 1.70.0)
set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
set(_Boost_COROUTINE_DEPENDENCIES context)
set(_Boost_FIBER_DEPENDENCIES context)
@@ -886,7 +1106,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
else()
- if(NOT Boost_VERSION VERSION_LESS 107000)
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.70.0)
set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
set(_Boost_COROUTINE_DEPENDENCIES context)
set(_Boost_FIBER_DEPENDENCIES context)
@@ -901,7 +1121,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
endif()
- if(NOT Boost_VERSION VERSION_LESS 107100)
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.71.0)
message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets")
endif()
endif()
@@ -939,7 +1159,7 @@ function(_Boost_COMPONENT_HEADERS component _hdrs)
set(_Boost_CHRONO_HEADERS "boost/chrono.hpp")
set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp")
set(_Boost_CONTRACT_HEADERS "boost/contract.hpp")
- if(Boost_VERSION VERSION_LESS 106100)
+ if(Boost_VERSION_STRING VERSION_LESS 1.61.0)
set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp")
else()
set(_Boost_CONTEXT_HEADERS "boost/context/detail/fcontext.hpp")
@@ -1058,7 +1278,7 @@ endfunction()
#
function(_Boost_COMPILER_FEATURES component _ret)
# Boost >= 1.62
- if(NOT Boost_VERSION VERSION_LESS 106200)
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0)
set(_Boost_FIBER_COMPILER_FEATURES
cxx_alias_templates
cxx_auto_type
@@ -1204,26 +1424,12 @@ else()
endif()
endif()
-# The reason that we failed to find Boost. This will be set to a
-# user-friendly message when we fail to find some necessary piece of
-# Boost.
-set(Boost_ERROR_REASON)
-
-if(Boost_DEBUG)
- # Output some of their choices
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_TEST_VERSIONS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_MULTITHREADED")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_LIBS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_RUNTIME")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_ADDITIONAL_VERSIONS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NO_SYSTEM_PATHS")
# Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It
# will only contain any interface definitions on WIN32, but is created
@@ -1234,6 +1440,8 @@ if(NOT TARGET Boost::diagnostic_definitions)
add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
add_library(Boost::disable_autolinking INTERFACE IMPORTED)
add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+ set_target_properties(Boost::dynamic_linking PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
endif()
if(WIN32)
# In windows, automatic linking is performed, so you do not have
@@ -1258,11 +1466,13 @@ if(WIN32)
INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
set_target_properties(Boost::disable_autolinking PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
- set_target_properties(Boost::dynamic_linking PROPERTIES
- INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
endif()
-_Boost_CHECK_SPELLING(Boost_ROOT)
+cmake_policy(GET CMP0074 _Boost_CMP0074)
+if(NOT "x${_Boost_CMP0074}x" STREQUAL "xNEWx")
+ _Boost_CHECK_SPELLING(Boost_ROOT)
+endif()
+unset(_Boost_CMP0074)
_Boost_CHECK_SPELLING(Boost_LIBRARYDIR)
_Boost_CHECK_SPELLING(Boost_INCLUDEDIR)
@@ -1288,18 +1498,12 @@ set(_Boost_VARS_DIR
Boost_NO_SYSTEM_PATHS
)
-if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Declared as CMake or Environmental Variables:")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " BOOST_ROOT = ${BOOST_ROOT}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT" ENVIRONMENT)
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR" ENVIRONMENT)
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR" ENVIRONMENT)
# ------------------------------------------------------------------------
# Search for Boost include DIR
@@ -1371,14 +1575,8 @@ if(NOT Boost_INCLUDE_DIR)
endforeach()
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Include debugging info:")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}")
- endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_INCLUDE_SEARCH_DIRS")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_PATH_SUFFIXES")
# Look for a standard boost header file.
find_path(Boost_INCLUDE_DIR
@@ -1392,74 +1590,54 @@ endif()
# Extract version information from version.hpp
# ------------------------------------------------------------------------
-# Set Boost_FOUND based only on header location and version.
-# It will be updated below for component libraries.
if(Boost_INCLUDE_DIR)
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp")
- endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp")
- # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp
- set(Boost_VERSION 0)
+ # Extract Boost_VERSION_MACRO and Boost_LIB_VERSION from version.hpp
+ set(Boost_VERSION_MACRO 0)
set(Boost_LIB_VERSION "")
file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ")
- set(_Boost_VERSION_REGEX "([0-9]+)")
- set(_Boost_LIB_VERSION_REGEX "\"([0-9_]+)\"")
- foreach(v VERSION LIB_VERSION)
- if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_${v} ${_Boost_${v}_REGEX}")
- set(Boost_${v} "${CMAKE_MATCH_1}")
- endif()
- endforeach()
+ if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_VERSION ([0-9]+)")
+ set(Boost_VERSION_MACRO "${CMAKE_MATCH_1}")
+ endif()
+ if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"")
+ set(Boost_LIB_VERSION "${CMAKE_MATCH_1}")
+ endif()
unset(_boost_VERSION_HPP_CONTENTS)
- math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000")
- math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000")
- math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100")
- set(Boost_VERSION_STRING "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}")
+ # Calculate version components
+ math(EXPR Boost_VERSION_MAJOR "${Boost_VERSION_MACRO} / 100000")
+ math(EXPR Boost_VERSION_MINOR "${Boost_VERSION_MACRO} / 100 % 1000")
+ math(EXPR Boost_VERSION_PATCH "${Boost_VERSION_MACRO} % 100")
+ set(Boost_VERSION_COUNT 3)
- string(APPEND Boost_ERROR_REASON
- "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}")
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "version.hpp reveals boost "
- "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}")
- endif()
+ # Define alias variables for backwards compat.
+ set(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR})
+ set(Boost_MINOR_VERSION ${Boost_VERSION_MINOR})
+ set(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH})
- if(Boost_FIND_VERSION)
- # Set Boost_FOUND based on requested version.
- set(_Boost_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}")
- if("${_Boost_VERSION}" VERSION_LESS "${Boost_FIND_VERSION}")
- set(Boost_FOUND 0)
- set(_Boost_VERSION_AGE "old")
- elseif(Boost_FIND_VERSION_EXACT AND
- NOT "${_Boost_VERSION}" VERSION_EQUAL "${Boost_FIND_VERSION}")
- set(Boost_FOUND 0)
- set(_Boost_VERSION_AGE "new")
- else()
- set(Boost_FOUND 1)
- endif()
- if(NOT Boost_FOUND)
- # State that we found a version of Boost that is too new or too old.
- string(APPEND Boost_ERROR_REASON
- "\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}")
- if (Boost_FIND_VERSION_PATCH)
- string(APPEND Boost_ERROR_REASON
- ".${Boost_FIND_VERSION_PATCH}")
- endif ()
- if (NOT Boost_FIND_VERSION_EXACT)
- string(APPEND Boost_ERROR_REASON " (or newer)")
- endif ()
- string(APPEND Boost_ERROR_REASON ".")
- endif ()
+ # Define Boost version in x.y.z format
+ set(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}")
+
+ # Define final Boost_VERSION
+ cmake_policy(GET CMP0093 _Boost_CMP0093
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_Boost_CMP0093}x" STREQUAL "xNEWx")
+ set(Boost_VERSION ${Boost_VERSION_STRING})
else()
- # Caller will accept any Boost version.
- set(Boost_FOUND 1)
+ set(Boost_VERSION ${Boost_VERSION_MACRO})
endif()
-else()
- set(Boost_FOUND 0)
- string(APPEND Boost_ERROR_REASON
- "Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.")
+ unset(_Boost_CMP0093)
+
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_STRING")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MACRO")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MAJOR")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MINOR")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_PATCH")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_COUNT")
endif()
# ------------------------------------------------------------------------
@@ -1476,12 +1654,8 @@ if ( NOT Boost_NAMESPACE )
set(Boost_NAMESPACE "boost")
endif()
-if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_LIB_PREFIX = ${Boost_LIB_PREFIX}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Boost_NAMESPACE = ${Boost_NAMESPACE}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_LIB_PREFIX")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NAMESPACE")
# ------------------------------------------------------------------------
# Suffix initialization and compiler suffix detection.
@@ -1503,30 +1677,21 @@ _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME})
# Setting some more suffixes for the library
if (Boost_COMPILER)
set(_boost_COMPILER ${Boost_COMPILER})
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "using user-specified Boost_COMPILER = ${_boost_COMPILER}")
- endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_COMPILER" SOURCE "user-specified via Boost_COMPILER")
else()
# Attempt to guess the compiler suffix
# NOTE: this is not perfect yet, if you experience any issues
# please report them and use the Boost_COMPILER variable
# to work around the problems.
_Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER)
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "guessed _boost_COMPILER = ${_boost_COMPILER}")
- endif()
endif()
set (_boost_MULTITHREADED "-mt")
if( NOT Boost_USE_MULTITHREADED )
set (_boost_MULTITHREADED "")
endif()
-if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_MULTITHREADED = ${_boost_MULTITHREADED}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_MULTITHREADED")
#======================
# Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts
@@ -1577,14 +1742,12 @@ endif()
# Only used in 'versioned' layout, added in Boost 1.66.0
if(DEFINED Boost_ARCHITECTURE)
set(_boost_ARCHITECTURE_TAG "${Boost_ARCHITECTURE}")
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "using user-specified Boost_ARCHITECTURE = ${_boost_ARCHITECTURE_TAG}")
- endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_ARCHITECTURE_TAG" SOURCE "user-specified via Boost_ARCHITECTURE")
else()
set(_boost_ARCHITECTURE_TAG "")
# {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers
- if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION VERSION_LESS 106600)
+ if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION_STRING VERSION_LESS 1.66.0)
string(APPEND _boost_ARCHITECTURE_TAG "-")
# This needs to be kept in-sync with the section of CMakePlatformId.h.in
# inside 'defined(_WIN32) && defined(_MSC_VER)'
@@ -1605,14 +1768,12 @@ else()
string(APPEND _boost_ARCHITECTURE_TAG "32")
endif()
endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_ARCHITECTURE_TAG" SOURCE "detected")
endif()
-if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}")
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_RELEASE_ABI_TAG")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_DEBUG_ABI_TAG")
# ------------------------------------------------------------------------
# Begin finding boost libraries
@@ -1672,11 +1833,8 @@ foreach(c DEBUG RELEASE)
endif()
endforeach()
-if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "_boost_LIBRARY_SEARCH_DIRS_RELEASE = ${_boost_LIBRARY_SEARCH_DIRS_RELEASE}"
- "_boost_LIBRARY_SEARCH_DIRS_DEBUG = ${_boost_LIBRARY_SEARCH_DIRS_DEBUG}")
-endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_RELEASE")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG")
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if( Boost_USE_STATIC_LIBS )
@@ -1716,10 +1874,10 @@ endif()
# On versions < 1.35, remove the System library from the considered list
# since it wasn't added until 1.35.
-if(Boost_VERSION AND Boost_FIND_COMPONENTS)
- if(Boost_VERSION LESS 103500)
- list(REMOVE_ITEM Boost_FIND_COMPONENTS system)
- endif()
+if(Boost_VERSION_STRING AND Boost_FIND_COMPONENTS)
+ if(Boost_VERSION_STRING VERSION_LESS 1.35.0)
+ list(REMOVE_ITEM Boost_FIND_COMPONENTS system)
+ endif()
endif()
# Additional components may be required via component dependencies.
@@ -1801,19 +1959,13 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS})
# Consolidate and report component-specific hints.
if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME)
list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME)
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Component-specific library search names for ${COMPONENT_NAME}: "
- "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}")
- endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Component-specific library search names for ${COMPONENT_NAME}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}")
endif()
if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT)
list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT)
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Component-specific library search paths for ${COMPONENT}: "
- "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}")
- endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Component-specific library search paths for ${COMPONENT}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}")
endif()
#
@@ -1866,10 +2018,8 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS})
if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread")
_Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES})
endif()
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}")
- endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}")
# if Boost_LIBRARY_DIR_RELEASE is not defined,
# but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs
@@ -1923,10 +2073,8 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS})
if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread")
_Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES})
endif()
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
- "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}")
- endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}")
# if Boost_LIBRARY_DIR_DEBUG is not defined,
# but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs
@@ -1979,57 +2127,25 @@ if(Boost_LIBRARY_DIRS)
list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS)
endif()
-# The above setting of Boost_FOUND was based only on the header files.
-# Update it for the requested component libraries.
-if(Boost_FOUND)
- # The headers were found. Check for requested component libs.
- set(_boost_CHECKED_COMPONENT FALSE)
- set(_Boost_MISSING_COMPONENTS "")
- foreach(COMPONENT ${Boost_FIND_COMPONENTS})
- string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
- set(_boost_CHECKED_COMPONENT TRUE)
- if(NOT Boost_${UPPERCOMPONENT}_FOUND AND Boost_FIND_REQUIRED_${COMPONENT})
- list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT})
- endif()
- endforeach()
- if(_Boost_MISSING_COMPONENTS AND _Boost_EXTRA_FIND_COMPONENTS)
- # Optional indirect dependencies are not counted as missing.
- list(REMOVE_ITEM _Boost_MISSING_COMPONENTS ${_Boost_EXTRA_FIND_COMPONENTS})
- endif()
+# ------------------------------------------------------------------------
+# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html
+# ------------------------------------------------------------------------
- if(Boost_DEBUG)
- message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}")
+# Define aliases as needed by the component handler in the FPHSA helper below
+foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${_comp} _uppercomp)
+ if(DEFINED Boost_${_uppercomp}_FOUND)
+ set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND})
endif()
+endforeach()
- if (_Boost_MISSING_COMPONENTS)
- set(Boost_FOUND 0)
- # We were unable to find some libraries, so generate a sensible
- # error message that lists the libraries we were unable to find.
- string(APPEND Boost_ERROR_REASON
- "\nCould not find the following")
- if(Boost_USE_STATIC_LIBS)
- string(APPEND Boost_ERROR_REASON " static")
- endif()
- string(APPEND Boost_ERROR_REASON
- " Boost libraries:\n")
- foreach(COMPONENT ${_Boost_MISSING_COMPONENTS})
- string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
- string(APPEND Boost_ERROR_REASON
- " ${Boost_NAMESPACE}_${COMPONENT}${Boost_ERROR_REASON_${UPPERCOMPONENT}}\n")
- endforeach()
-
- list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED)
- list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS)
- if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS})
- string(APPEND Boost_ERROR_REASON
- "No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.")
- else ()
- string(APPEND Boost_ERROR_REASON
- "Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.")
- endif ()
- endif ()
+find_package_handle_standard_args(Boost
+ REQUIRED_VARS Boost_INCLUDE_DIR
+ VERSION_VAR Boost_VERSION_STRING
+ HANDLE_COMPONENTS)
- if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT )
+if(Boost_FOUND)
+ if( NOT Boost_LIBRARY_DIRS )
# Compatibility Code for backwards compatibility with CMake
# 2.4's FindBoost module.
@@ -2073,15 +2189,24 @@ endif()
# ------------------------------------------------------------------------
if(Boost_FOUND)
- # For header-only libraries
- if(NOT TARGET Boost::boost)
- add_library(Boost::boost INTERFACE IMPORTED)
+ # The builtin CMake package in Boost 1.70+ introduces a new name
+ # for the header-only lib, let's provide the same UI in module mode
+ if(NOT TARGET Boost::headers)
+ add_library(Boost::headers INTERFACE IMPORTED)
if(Boost_INCLUDE_DIRS)
- set_target_properties(Boost::boost PROPERTIES
+ set_target_properties(Boost::headers PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")
endif()
endif()
+ # Define the old target name for header-only libraries for backwards
+ # compat.
+ if(NOT TARGET Boost::boost)
+ add_library(Boost::boost INTERFACE IMPORTED)
+ set_target_properties(Boost::boost
+ PROPERTIES INTERFACE_LINK_LIBRARIES Boost::headers)
+ endif()
+
foreach(COMPONENT ${Boost_FIND_COMPONENTS})
if(_Boost_IMPORTED_TARGETS AND NOT TARGET Boost::${COMPONENT})
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
@@ -2137,46 +2262,20 @@ if(Boost_FOUND)
endif()
# ------------------------------------------------------------------------
-# Notification to end user about what was found
+# Finalize
# ------------------------------------------------------------------------
+# Report Boost_LIBRARIES
set(Boost_LIBRARIES "")
-if(Boost_FOUND)
- if(NOT Boost_FIND_QUIETLY)
- message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}")
- if(Boost_FIND_COMPONENTS)
- message(STATUS "Found the following Boost libraries:")
- endif()
- endif()
- foreach( COMPONENT ${Boost_FIND_COMPONENTS} )
- string( TOUPPER ${COMPONENT} UPPERCOMPONENT )
- if( Boost_${UPPERCOMPONENT}_FOUND )
- if(NOT Boost_FIND_QUIETLY)
- message (STATUS " ${COMPONENT}")
- endif()
- list(APPEND Boost_LIBRARIES ${Boost_${UPPERCOMPONENT}_LIBRARY})
- if(COMPONENT STREQUAL "thread")
- list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
- endif()
- endif()
- endforeach()
-else()
- if(Boost_FIND_REQUIRED)
- message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}")
- else()
- if(NOT Boost_FIND_QUIETLY)
- # we opt not to automatically output Boost_ERROR_REASON here as
- # it could be quite lengthy and somewhat imposing in its requests
- # Since Boost is not always a required dependency we'll leave this
- # up to the end-user.
- if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG)
- message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}")
- else()
- message(STATUS "Could NOT find Boost")
- endif()
+foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${_comp} _uppercomp)
+ if(Boost_${_uppercomp}_FOUND)
+ list(APPEND Boost_LIBRARIES ${Boost_${_uppercomp}_LIBRARY})
+ if(_comp STREQUAL "thread")
+ list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif()
endif()
-endif()
+endforeach()
# Configure display of cache entries in GUI.
foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB})
diff --git a/Modules/FindBullet.cmake b/Modules/FindBullet.cmake
index a3c9fc6d1..6d6418521 100644
--- a/Modules/FindBullet.cmake
+++ b/Modules/FindBullet.cmake
@@ -52,12 +52,12 @@ macro(_FIND_BULLET_LIBRARY _var)
endmacro()
macro(_BULLET_APPEND_LIBRARIES _list _release)
- set(_debug ${_release}_DEBUG)
- if(${_debug})
- set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}})
- else()
- set(${_list} ${${_list}} ${${_release}})
- endif()
+ set(_debug ${_release}_DEBUG)
+ if(${_debug})
+ set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}})
+ else()
+ set(${_list} ${${_list}} ${${_release}})
+ endif()
endmacro()
find_path(BULLET_INCLUDE_DIR NAMES btBulletCollisionCommon.h
diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake
index 228eed4f7..33155059a 100644
--- a/Modules/FindCUDA.cmake
+++ b/Modules/FindCUDA.cmake
@@ -538,7 +538,7 @@ if(DEFINED ENV{CUDAHOSTCXX})
elseif(CMAKE_GENERATOR MATCHES "Visual Studio")
set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)Tools/MSVC/$(VCToolsVersion)/bin/Host$(Platform)/$(PlatformTarget)")
if(MSVC_VERSION LESS 1910)
- set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin")
+ set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin")
endif()
set(CUDA_HOST_COMPILER "${_CUDA_MSVC_HOST_COMPILER}" CACHE FILEPATH "Host side compiler used by NVCC")
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
index b1989b10e..aeebc842e 100644
--- a/Modules/FindCURL.cmake
+++ b/Modules/FindCURL.cmake
@@ -27,16 +27,16 @@ Result Variables
This module defines the following variables:
``CURL_FOUND``
- True if curl found.
+ "True" if ``curl`` found.
``CURL_INCLUDE_DIRS``
- where to find curl/curl.h, etc.
+ where to find ``curl``/``curl.h``, etc.
``CURL_LIBRARIES``
- List of libraries when using curl.
+ List of libraries when using ``curl``.
``CURL_VERSION_STRING``
- The version of curl found.
+ The version of ``curl`` found.
#]=======================================================================]
find_package(PkgConfig QUIET)
diff --git a/Modules/FindCVS.cmake b/Modules/FindCVS.cmake
index 89dbc0e10..f81980039 100644
--- a/Modules/FindCVS.cmake
+++ b/Modules/FindCVS.cmake
@@ -5,7 +5,7 @@
FindCVS
-------
-
+Find the Concurrent Versions System (CVS).
The module defines the following variables:
diff --git a/Modules/FindCups.cmake b/Modules/FindCups.cmake
index 10ce22968..4e8232d07 100644
--- a/Modules/FindCups.cmake
+++ b/Modules/FindCups.cmake
@@ -5,18 +5,38 @@
FindCups
--------
-Try to find the Cups printing system
+Find the Common UNIX Printing System (CUPS).
-Once done this will define
+Set ``CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE`` to ``TRUE`` if you need a version which
+features this function (i.e. at least ``1.1.19``)
-::
+Imported targets
+^^^^^^^^^^^^^^^^
- CUPS_FOUND - system has Cups
- CUPS_INCLUDE_DIR - the Cups include directory
- CUPS_LIBRARIES - Libraries needed to use Cups
- CUPS_VERSION_STRING - version of Cups found (since CMake 2.8.8)
- Set CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE to TRUE if you need a version which
- features this function (i.e. at least 1.1.19)
+This module defines :prop_tgt:`IMPORTED` target ``Cups::Cups``, if Cups has
+been found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``CUPS_FOUND``
+ true if CUPS headers and libraries were found
+``CUPS_INCLUDE_DIRS``
+ the directory containing the Cups headers
+``CUPS_LIBRARIES``
+ the libraries to link against to use CUPS.
+``CUPS_VERSION_STRING``
+ the version of CUPS found (since CMake 2.8.8)
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``CUPS_INCLUDE_DIR``
+ the directory containing the Cups headers
#]=======================================================================]
find_path(CUPS_INCLUDE_DIR cups/cups.h )
@@ -66,3 +86,13 @@ else ()
endif ()
mark_as_advanced(CUPS_INCLUDE_DIR CUPS_LIBRARIES)
+
+if (CUPS_FOUND)
+ set(CUPS_INCLUDE_DIRS "${CUPS_INCLUDE_DIR}")
+ if (NOT TARGET Cups::Cups)
+ add_library(Cups::Cups INTERFACE IMPORTED)
+ set_target_properties(Cups::Cups PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${CUPS_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${CUPS_INCLUDE_DIR}")
+ endif ()
+endif ()
diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake
index c22584782..b3cd8fa49 100644
--- a/Modules/FindCurses.cmake
+++ b/Modules/FindCurses.cmake
@@ -141,7 +141,7 @@ if(CURSES_USE_NCURSES)
NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h
HINTS "${_cursesParentDir}/include"
)
- endif()
+ endif()
# Previous versions of FindCurses provided these values.
if(NOT DEFINED CURSES_LIBRARY)
diff --git a/Modules/FindCxxTest.cmake b/Modules/FindCxxTest.cmake
index 4eec5fcec..3fc0e938a 100644
--- a/Modules/FindCxxTest.cmake
+++ b/Modules/FindCxxTest.cmake
@@ -5,7 +5,7 @@
FindCxxTest
-----------
-Find CxxTest
+Find CxxTest unit testing framework.
Find the CxxTest suite and declare a helper macro for creating unit
tests and integrating them with CTest. For more details on CxxTest
@@ -194,7 +194,7 @@ endmacro()
# main()
#=============================================================
if(NOT DEFINED CXXTEST_TESTGEN_ARGS)
- set(CXXTEST_TESTGEN_ARGS --error-printer)
+ set(CXXTEST_TESTGEN_ARGS --error-printer)
endif()
find_package(Python QUIET)
@@ -208,40 +208,40 @@ find_program(CXXTEST_PERL_TESTGEN_EXECUTABLE cxxtestgen.pl
PATHS ${CXXTEST_INCLUDE_DIR})
if(PYTHON_FOUND OR PERL_FOUND)
- include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
-
- if(PYTHON_FOUND AND (CXXTEST_USE_PYTHON OR NOT PERL_FOUND OR NOT DEFINED CXXTEST_USE_PYTHON))
- set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE})
- execute_process(COMMAND ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE} --version
- OUTPUT_VARIABLE _CXXTEST_OUT ERROR_VARIABLE _CXXTEST_OUT RESULT_VARIABLE _CXXTEST_RESULT)
- if(_CXXTEST_RESULT EQUAL 0)
- set(CXXTEST_TESTGEN_INTERPRETER "")
- else()
- set(CXXTEST_TESTGEN_INTERPRETER ${Python_EXECUTABLE})
- endif()
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
- CXXTEST_INCLUDE_DIR CXXTEST_PYTHON_TESTGEN_EXECUTABLE)
-
- elseif(PERL_FOUND)
- set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PERL_TESTGEN_EXECUTABLE})
- set(CXXTEST_TESTGEN_INTERPRETER ${PERL_EXECUTABLE})
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
- CXXTEST_INCLUDE_DIR CXXTEST_PERL_TESTGEN_EXECUTABLE)
- endif()
-
- if(CXXTEST_FOUND)
- set(CXXTEST_INCLUDE_DIRS ${CXXTEST_INCLUDE_DIR})
- endif()
+ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+ if(PYTHON_FOUND AND (CXXTEST_USE_PYTHON OR NOT PERL_FOUND OR NOT DEFINED CXXTEST_USE_PYTHON))
+ set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE})
+ execute_process(COMMAND ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE} --version
+ OUTPUT_VARIABLE _CXXTEST_OUT ERROR_VARIABLE _CXXTEST_OUT RESULT_VARIABLE _CXXTEST_RESULT)
+ if(_CXXTEST_RESULT EQUAL 0)
+ set(CXXTEST_TESTGEN_INTERPRETER "")
+ else()
+ set(CXXTEST_TESTGEN_INTERPRETER ${Python_EXECUTABLE})
+ endif()
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
+ CXXTEST_INCLUDE_DIR CXXTEST_PYTHON_TESTGEN_EXECUTABLE)
+
+ elseif(PERL_FOUND)
+ set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PERL_TESTGEN_EXECUTABLE})
+ set(CXXTEST_TESTGEN_INTERPRETER ${PERL_EXECUTABLE})
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
+ CXXTEST_INCLUDE_DIR CXXTEST_PERL_TESTGEN_EXECUTABLE)
+ endif()
+
+ if(CXXTEST_FOUND)
+ set(CXXTEST_INCLUDE_DIRS ${CXXTEST_INCLUDE_DIR})
+ endif()
else()
- set(CXXTEST_FOUND false)
- if(NOT CxxTest_FIND_QUIETLY)
- if(CxxTest_FIND_REQUIRED)
- message(FATAL_ERROR "Neither Python nor Perl found, cannot use CxxTest, aborting!")
- else()
- message(STATUS "Neither Python nor Perl found, CxxTest will not be used.")
- endif()
- endif()
+ set(CXXTEST_FOUND false)
+ if(NOT CxxTest_FIND_QUIETLY)
+ if(CxxTest_FIND_REQUIRED)
+ message(FATAL_ERROR "Neither Python nor Perl found, cannot use CxxTest, aborting!")
+ else()
+ message(STATUS "Neither Python nor Perl found, CxxTest will not be used.")
+ endif()
+ endif()
endif()
diff --git a/Modules/FindCygwin.cmake b/Modules/FindCygwin.cmake
index 8811623a2..5bbc802a0 100644
--- a/Modules/FindCygwin.cmake
+++ b/Modules/FindCygwin.cmake
@@ -5,7 +5,8 @@
FindCygwin
----------
-this module looks for Cygwin
+Find Cygwin, a POSIX-compatible environment that runs natively
+on Microsoft Windows
#]=======================================================================]
if (WIN32)
diff --git a/Modules/FindDCMTK.cmake b/Modules/FindDCMTK.cmake
index 111e0ff2f..d48de0896 100644
--- a/Modules/FindDCMTK.cmake
+++ b/Modules/FindDCMTK.cmake
@@ -5,7 +5,7 @@
FindDCMTK
---------
-Find DCMTK libraries and applications
+Find DICOM ToolKit (DCMTK) libraries and applications
The module defines the following variables::
diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake
index 32b4aa2c8..ebd0b24ab 100644
--- a/Modules/FindDoxygen.cmake
+++ b/Modules/FindDoxygen.cmake
@@ -974,7 +974,7 @@ doxygen_add_docs() for target ${targetName}")
"${DOXYGEN_OUTPUT_DIRECTORY}/${DOXYGEN_HTML_OUTPUT}")
endif()
set_property(DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES "${_args_clean_html_dir}")
+ ADDITIONAL_CLEAN_FILES "${_args_clean_html_dir}")
endif()
# Build up a list of files we can identify from the inputs so we can list
diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake
index 58e08418c..15b419a61 100644
--- a/Modules/FindEXPAT.cmake
+++ b/Modules/FindEXPAT.cmake
@@ -6,6 +6,7 @@ FindEXPAT
---------
Find the native Expat headers and library.
+Expat is a stream-oriented XML parser library written in C.
Imported Targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindEnvModules.cmake b/Modules/FindEnvModules.cmake
new file mode 100644
index 000000000..4dd5116cd
--- /dev/null
+++ b/Modules/FindEnvModules.cmake
@@ -0,0 +1,333 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindEnvModules
+--------------
+
+Locate an environment module implementation and make commands available to
+CMake scripts to use them. This is compatible with both Lua-based Lmod
+and TCL-based EnvironmentModules.
+
+This module is intended for the use case of setting up the compiler and library
+environment within a :ref:`CTest Script <CTest Script>` (``ctest -S``). It can
+also be used in a :ref:`CMake Script <Script Processing Mode>` (``cmake -P``).
+
+.. note::
+
+ The loaded environment will not survive past the end of the calling process.
+ Do not use this module in project code (``CMakeLists.txt`` files) to load
+ a compiler environment; it will not be available during the build. Instead
+ load the environment manually before running CMake or using the generated
+ build system.
+
+Example Usage
+^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ set(CTEST_BUILD_NAME "CrayLinux-CrayPE-Cray-dynamic")
+ set(CTEST_BUILD_CONFIGURATION Release)
+ set(CTEST_BUILD_FLAGS "-k -j8")
+ set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
+
+ ...
+
+ find_package(EnvModules REQUIRED)
+
+ env_module(purge)
+ env_module(load modules)
+ env_module(load craype)
+ env_module(load PrgEnv-cray)
+ env_module(load craype-knl)
+ env_module(load cray-mpich)
+ env_module(load cray-libsci)
+
+ set(ENV{CRAYPE_LINK_TYPE} dynamic)
+
+ ...
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``EnvModules_FOUND``
+ True if a compatible environment modules framework was found.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variable will be set:
+
+``EnvModules_COMMAND``
+ The low level module command to use. Currently supported
+ implementations are the Lua based Lmod and TCL based EnvironmentModules.
+
+Environment Variables
+^^^^^^^^^^^^^^^^^^^^^
+
+``ENV{MODULESHOME}``
+ Usually set by the module environment implementation, used as a hint to
+ locate the module command to execute.
+
+Provided Functions
+^^^^^^^^^^^^^^^^^^
+
+This defines the following CMake functions for interacting with environment
+modules:
+
+.. command:: env_module
+
+ Execute an aribitrary module command:
+
+ .. code-block:: cmake
+
+ env_module(cmd arg1 ... argN)
+ env_module(
+ COMMAND cmd arg1 ... argN
+ [OUTPUT_VARIABLE <out-var>]
+ [RESULT_VARIABLE <ret-var>]
+ )
+
+ The options are:
+
+ ``cmd arg1 ... argN``
+ The module sub-command and arguments to execute as if they were
+ passed directly to the module command in your shell environment.
+
+ ``OUTPUT_VARIABLE <out-var>``
+ The standard output from executing the module command.
+
+ ``RESULT_VARIABLE <ret-var>``
+ The return code from executing the module command.
+
+.. command:: env_module_swap
+
+ Swap one module for another:
+
+ .. code-block:: cmake
+
+ env_module_swap(out_mod in_mod
+ [OUTPUT_VARIABLE <out-var>]
+ [RESULT_VARIABLE <ret-var>]
+ )
+
+ This is functionally equivalent to the ``module swap out_mod in_mod`` shell
+ command. The options are:
+
+ ``OUTPUT_VARIABLE <out-var>``
+ The standard output from executing the module command.
+
+ ``RESULT_VARIABLE <ret-var>``
+ The return code from executing the module command.
+
+.. command:: env_module_list
+
+ Retrieve the list of currently loaded modules:
+
+ .. code-block:: cmake
+
+ env_module_list(<out-var>)
+
+ This is functionally equivalent to the ``module list`` shell command.
+ The result is stored in ``<out-var>`` as a properly formatted CMake
+ :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+.. command:: env_module_avail
+
+ Retrieve the list of available modules:
+
+ .. code-block:: cmake
+
+ env_module_avail([<mod-prefix>] <out-var>)
+
+ This is functionally equivalent to the ``module avail <mod-prefix>`` shell
+ command. The result is stored in ``<out-var>`` as a properly formatted
+ CMake :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+#]=======================================================================]
+
+function(env_module)
+ if(NOT EnvModules_COMMAND)
+ message(FATAL_ERROR "Failed to process module command. EnvModules_COMMAND not found")
+ return()
+ endif()
+
+ set(options)
+ set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+ set(multiValueArgs COMMAND)
+ cmake_parse_arguments(MOD_ARGS
+ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+ )
+ if(NOT MOD_ARGS_COMMAND)
+ # If no explicit command argument was given, then treat the calling syntax
+ # as: module(cmd args...)
+ set(exec_cmd ${ARGV})
+ else()
+ set(exec_cmd ${MOD_ARGS_COMMAND})
+ endif()
+
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(err_var_args ERROR_VARIABLE err_var)
+ endif()
+
+ execute_process(
+ COMMAND mktemp -t module.cmake.XXXXXXXXXXXX
+ OUTPUT_VARIABLE tempfile_name
+ )
+ string(STRIP "${tempfile_name}" tempfile_name)
+
+ # If the $MODULESHOME/init/cmake file exists then assume that the CMake
+ # "shell" functionality exits
+ if(EXISTS "$ENV{MODULESHOME}/init/cmake")
+ execute_process(
+ COMMAND ${EnvModules_COMMAND} cmake ${exec_cmd}
+ OUTPUT_FILE ${tempfile_name}
+ ${err_var_args}
+ RESULT_VARIABLE ret_var
+ )
+
+ else() # fallback to the sh shell and manually convert to CMake
+ execute_process(
+ COMMAND ${EnvModules_COMMAND} sh ${exec_cmd}
+ OUTPUT_VARIABLE out_var
+ ${err_var_args}
+ RESULT_VARIABLE ret_var
+ )
+ endif()
+
+ # If we executed successfully then process and cleanup the temp file
+ if(ret_var EQUAL 0)
+ # No CMake shell so we need to process the sh output into CMake code
+ if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake")
+ file(WRITE ${tempfile_name} "")
+ string(REPLACE "\n" ";" out_var "${out_var}")
+ foreach(sh_cmd IN LISTS out_var)
+ if(sh_cmd MATCHES "^ *unset *([^ ]*)")
+ set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})")
+ elseif(sh_cmd MATCHES "^ *export *([^ ]*)")
+ set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")")
+ elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)")
+ set(var_name "${CMAKE_MATCH_1}")
+ set(var_value "${CMAKE_MATCH_2}")
+ if(var_value MATCHES "^\"(.*[^\\])\"")
+ # If it's in quotes, take the value as is
+ set(var_value "${CMAKE_MATCH_1}")
+ else()
+ # Otherwise, strip trailing spaces
+ string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}")
+ endif()
+ string(REPLACE "\\ " " " var_value "${var_value}")
+ set(cmake_cmd "set(${var_name} \"${var_value}\")")
+ else()
+ continue()
+ endif()
+ file(APPEND ${tempfile_name} "${cmake_cmd}\n")
+ endforeach()
+ endif()
+
+ # Process the change in environment variables
+ include(${tempfile_name})
+ file(REMOVE ${tempfile_name})
+ endif()
+
+ # Push the output back out to the calling scope
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+ endif()
+ if(MOD_ARGS_RESULT_VARIABLE)
+ set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE)
+ endif()
+endfunction(env_module)
+
+#------------------------------------------------------------------------------
+function(env_module_swap out_mod in_mod)
+ set(options)
+ set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+ set(multiValueArgs)
+
+ cmake_parse_arguments(MOD_ARGS
+ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+ )
+
+ env_module(COMMAND -t swap ${out_mod} ${in_mod}
+ OUTPUT_VARIABLE tmp_out
+ RETURN_VARIABLE tmp_ret
+ )
+
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+ endif()
+ if(MOD_ARGS_RESULT_VARIABLE)
+ set(${MOD_ARGS_RESULT_VARIABLE} ${tmp_ret} PARENT_SCOPE)
+ endif()
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_list out_var)
+ cmake_policy(SET CMP0007 NEW)
+ env_module(COMMAND -t list OUTPUT_VARIABLE tmp_out)
+
+ # Convert output into a CMake list
+ string(REPLACE "\n" ";" ${out_var} "${tmp_out}")
+
+ # Remove title headers and empty entries
+ list(REMOVE_ITEM ${out_var} "No modules loaded")
+ if(${out_var})
+ list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+ endif()
+ list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_avail)
+ cmake_policy(SET CMP0007 NEW)
+
+ if(ARGC EQUAL 1)
+ set(mod_prefix)
+ set(out_var ${ARGV0})
+ elseif(ARGC EQUAL 2)
+ set(mod_prefix ${ARGV0})
+ set(out_var ${ARGV1})
+ else()
+ message(FATAL_ERROR "Usage: env_module_avail([mod_prefix] out_var)")
+ endif()
+ env_module(COMMAND -t avail ${mod_prefix} OUTPUT_VARIABLE tmp_out)
+
+ # Convert output into a CMake list
+ string(REPLACE "\n" ";" tmp_out "${tmp_out}")
+
+ set(${out_var})
+ foreach(MOD IN LISTS tmp_out)
+ # Remove directory entries and empty values
+ if(MOD MATCHES "^(.*:)?$")
+ continue()
+ endif()
+
+ # Convert default modules
+ if(MOD MATCHES "^(.*)/$" ) # "foo/"
+ list(APPEND ${out_var} ${CMAKE_MATCH_1})
+ elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)"
+ list(APPEND ${out_var} ${CMAKE_MATCH_2})
+ list(APPEND ${out_var} ${CMAKE_MATCH_1})
+ else()
+ list(APPEND ${out_var} ${MOD})
+ endif()
+ endforeach()
+
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+# Make sure we know where the underlying module command is
+find_program(EnvModules_COMMAND
+ NAMES lmod modulecmd
+ HINTS ENV MODULESHOME
+ PATH_SUFFIXES libexec
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND)
diff --git a/Modules/FindFLEX.cmake b/Modules/FindFLEX.cmake
index edebe755c..d22b7ec67 100644
--- a/Modules/FindFLEX.cmake
+++ b/Modules/FindFLEX.cmake
@@ -5,7 +5,8 @@
FindFLEX
--------
-Find flex executable and provides a macro to generate custom build rules
+Find Fast Lexical Analyzer (Flex) executable and provides a macro
+to generate custom build rules
@@ -13,7 +14,7 @@ The module defines the following variables:
::
- FLEX_FOUND - true is flex executable is found
+ FLEX_FOUND - True is flex executable is found
FLEX_EXECUTABLE - the path to the flex executable
FLEX_VERSION - the version of flex
FLEX_LIBRARIES - The flex libraries
@@ -22,7 +23,7 @@ The module defines the following variables:
The minimum required version of flex can be specified using the
-standard syntax, e.g. find_package(FLEX 2.5.13)
+standard syntax, e.g. :command:`find_package(FLEX 2.5.13)`
@@ -35,10 +36,10 @@ If flex is found on the system, the module provides the macro:
[DEFINES_FILE <string>]
)
-which creates a custom command to generate the <FlexOutput> file from
-the <FlexInput> file. If COMPILE_FLAGS option is specified, the next
+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
+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:
@@ -61,8 +62,8 @@ defines a macro:
ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget)
which adds the required dependency between a scanner and a parser
-where <FlexTarget> and <BisonTarget> are the first parameters of
-respectively FLEX_TARGET and BISON_TARGET macros.
+where ``FlexTarget`` and ``BisonTarget`` are the first parameters of
+respectively ``FLEX_TARGET`` and ``BISON_TARGET`` macros.
::
@@ -94,6 +95,7 @@ respectively FLEX_TARGET and BISON_TARGET macros.
${BISON_MyParser_OUTPUTS}
${FLEX_MyScanner_OUTPUTS}
)
+ target_link_libraries(Foo ${FLEX_LIBRARIES})
====================================================================
#]=======================================================================]
diff --git a/Modules/FindFLTK.cmake b/Modules/FindFLTK.cmake
index 89122c045..e273642b5 100644
--- a/Modules/FindFLTK.cmake
+++ b/Modules/FindFLTK.cmake
@@ -5,14 +5,14 @@
FindFLTK
--------
-Find the FLTK library
+Find the Fast Light Toolkit (FLTK) library
Input Variables
^^^^^^^^^^^^^^^
By default this module will search for all of the FLTK components and
-add them to the FLTK_LIBRARIES variable. You can limit the components
-which get placed in FLTK_LIBRARIES by defining one or more of the
+add them to the ``FLTK_LIBRARIES`` variable. You can limit the components
+which get placed in ``FLTK_LIBRARIES`` by defining one or more of the
following three options:
``FLTK_SKIP_OPENGL``
diff --git a/Modules/FindFLTK2.cmake b/Modules/FindFLTK2.cmake
index 161d15c4a..a43f7a475 100644
--- a/Modules/FindFLTK2.cmake
+++ b/Modules/FindFLTK2.cmake
@@ -5,7 +5,7 @@
FindFLTK2
---------
-Find the native FLTK2 includes and library
+Find the native FLTK 2.0 includes and library
The following settings are defined
@@ -243,4 +243,3 @@ else()
endif()
endif()
endif()
-
diff --git a/Modules/FindGDAL.cmake b/Modules/FindGDAL.cmake
index 8522f9b59..fde84d488 100644
--- a/Modules/FindGDAL.cmake
+++ b/Modules/FindGDAL.cmake
@@ -5,7 +5,7 @@
FindGDAL
--------
-Find GDAL.
+Find Geospatial Data Abstraction Library (GDAL).
IMPORTED Targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindGIF.cmake b/Modules/FindGIF.cmake
index 9687b57e5..d5a143e81 100644
--- a/Modules/FindGIF.cmake
+++ b/Modules/FindGIF.cmake
@@ -5,7 +5,7 @@
FindGIF
-------
-This finds the GIF library (giflib)
+This finds the Graphics Interchange Format (GIF) library (``giflib``)
Imported targets
^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ Imported targets
This module defines the following :prop_tgt:`IMPORTED` target:
``GIF::GIF``
- The giflib library, if found.
+ The ``giflib`` library, if found.
Result variables
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index ad8a810b5..2e9a05239 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -7,64 +7,305 @@ FindGLEW
Find the OpenGL Extension Wrangler Library (GLEW)
-IMPORTED Targets
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module’s behavior:
+
+``GLEW_USE_STATIC_LIBS``
+ to find and create :prop_tgt:`IMPORTED` target for static linkage.
+
+``GLEW_VERBOSE``
+ to output a detailed log of this module.
+
+Imported Targets
^^^^^^^^^^^^^^^^
-This module defines the :prop_tgt:`IMPORTED` target ``GLEW::GLEW``,
-if GLEW has been found.
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+
+``GLEW::glew``
+ The GLEW shared library.
+``GLEW::glew_s``
+ The GLEW static library, if ``GLEW_USE_STATIC_LIBS`` is set to ``TRUE``.
+``GLEW::GLEW``
+ Duplicates either ``GLEW::glew`` or ``GLEW::glew_s`` based on availability.
Result Variables
^^^^^^^^^^^^^^^^
This module defines the following variables:
-::
+``GLEW_INCLUDE_DIRS``
+ include directories for GLEW
+``GLEW_LIBRARIES``
+ libraries to link against GLEW
+``GLEW_SHARED_LIBRARIES``
+ libraries to link against shared GLEW
+``GLEW_STATIC_LIBRARIES``
+ libraries to link against static GLEW
+``GLEW_FOUND``
+ true if GLEW has been found and can be used
+``GLEW_VERSION``
+ GLEW version
+``GLEW_VERSION_MAJOR``
+ GLEW major version
+``GLEW_VERSION_MINOR``
+ GLEW minor version
+``GLEW_VERSION_MICRO``
+ GLEW micro version
- GLEW_INCLUDE_DIRS - include directories for GLEW
- GLEW_LIBRARIES - libraries to link against GLEW
- GLEW_FOUND - true if GLEW has been found and can be used
#]=======================================================================]
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+find_package(GLEW CONFIG QUIET)
+
+if(GLEW_FOUND)
+ find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG)
+ return()
+endif()
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.")
+endif()
+
+
+function(__glew_set_find_library_suffix shared_or_static)
+ if(UNIX AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE)
+ elseif(UNIX AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+ elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
+ elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+ elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
+ elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a" PARENT_SCOPE)
+ endif()
+
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: CMAKE_FIND_LIBRARY_SUFFIXES for ${shared_or_static}: ${CMAKE_FIND_LIBRARY_SUFFIXES}")
+ endif()
+endfunction()
+
+
+if(GLEW_VERBOSE)
+ if(DEFINED GLEW_USE_STATIC_LIBS)
+ message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS: ${GLEW_USE_STATIC_LIBS}.")
+ else()
+ message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS is undefined. Treated as FALSE.")
+ endif()
+endif()
+
find_path(GLEW_INCLUDE_DIR GL/glew.h)
+mark_as_advanced(GLEW_INCLUDE_DIR)
+
+set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
-if(NOT GLEW_LIBRARY)
- find_library(GLEW_LIBRARY_RELEASE NAMES GLEW glew32 glew glew32s PATH_SUFFIXES lib64 libx32)
- find_library(GLEW_LIBRARY_DEBUG NAMES GLEWd glew32d glewd PATH_SUFFIXES lib64)
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}")
+ message(STATUS "FindGLEW: GLEW_INCLUDE_DIRS: ${GLEW_INCLUDE_DIRS}")
+endif()
- include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
- select_library_configurations(GLEW)
-endif ()
+if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64" OR "${CMAKE_GENERATOR}" MATCHES "Win64")
+ set(_arch "x64")
+else()
+ set(_arch "Win32")
+endif()
+
+
+set(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+__glew_set_find_library_suffix(SHARED)
+
+find_library(GLEW_SHARED_LIBRARY_RELEASE
+ NAMES GLEW glew glew32
+ PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+ PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_SHARED_LIBRARY_DEBUG
+ NAMES GLEWd glewd glew32d
+ PATH_SUFFIXES lib lib64
+ PATHS ENV GLEW_ROOT)
+
+
+__glew_set_find_library_suffix(STATIC)
+
+find_library(GLEW_STATIC_LIBRARY_RELEASE
+ NAMES GLEW glew glew32s
+ PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+ PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_STATIC_LIBRARY_DEBUG
+ NAMES GLEWds glewds glew32ds
+ PATH_SUFFIXES lib lib64
+ PATHS ENV GLEW_ROOT)
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES})
+unset(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES)
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+select_library_configurations(GLEW_SHARED)
+select_library_configurations(GLEW_STATIC)
+
+if(NOT GLEW_USE_STATIC_LIBS)
+ set(GLEW_LIBRARIES ${GLEW_SHARED_LIBRARY})
+else()
+ set(GLEW_LIBRARIES ${GLEW_STATIC_LIBRARY})
+endif()
+
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_RELEASE: ${GLEW_SHARED_LIBRARY_RELEASE}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_RELEASE: ${GLEW_STATIC_LIBRARY_RELEASE}")
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_DEBUG: ${GLEW_SHARED_LIBRARY_DEBUG}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_DEBUG: ${GLEW_STATIC_LIBRARY_DEBUG}")
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY: ${GLEW_SHARED_LIBRARY}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY: ${GLEW_STATIC_LIBRARY}")
+ message(STATUS "FindGLEW: GLEW_LIBRARIES: ${GLEW_LIBRARIES}")
+endif()
+
+
+# Read version from GL/glew.h file
+if(EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h")
+ file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" _contents REGEX "^VERSION_.+ [0-9]+")
+ if(_contents)
+ string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MAJOR "${_contents}")
+ string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MINOR "${_contents}")
+ string(REGEX REPLACE ".*VERSION_MICRO[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MICRO "${_contents}")
+ set(GLEW_VERSION "${GLEW_VERSION_MAJOR}.${GLEW_VERSION_MINOR}.${GLEW_VERSION_MICRO}")
+ endif()
+endif()
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_VERSION_MAJOR: ${GLEW_VERSION_MAJOR}")
+ message(STATUS "FindGLEW: GLEW_VERSION_MINOR: ${GLEW_VERSION_MINOR}")
+ message(STATUS "FindGLEW: GLEW_VERSION_MICRO: ${GLEW_VERSION_MICRO}")
+ message(STATUS "FindGLEW: GLEW_VERSION: ${GLEW_VERSION}")
+endif()
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args(GLEW
- REQUIRED_VARS GLEW_INCLUDE_DIR GLEW_LIBRARY)
+ REQUIRED_VARS GLEW_INCLUDE_DIRS GLEW_LIBRARIES
+ VERSION_VAR GLEW_VERSION)
-if(GLEW_FOUND)
- set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
+if(NOT GLEW_FOUND)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: could not found GLEW library.")
+ endif()
+ return()
+endif()
+
+
+if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::glew imported target.")
+ endif()
+
+ add_library(GLEW::glew UNKNOWN IMPORTED)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(GLEW_SHARED_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::glew
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_SHARED_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::glew
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
+ endif()
- if(NOT GLEW_LIBRARIES)
- set(GLEW_LIBRARIES ${GLEW_LIBRARY})
+elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::glew_s imported target.")
endif()
- if (NOT TARGET GLEW::GLEW)
- add_library(GLEW::GLEW UNKNOWN IMPORTED)
- set_target_properties(GLEW::GLEW PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+ add_library(GLEW::glew_s UNKNOWN IMPORTED)
- if(GLEW_LIBRARY_RELEASE)
- set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
- set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_LIBRARY_RELEASE}")
+ set_target_properties(GLEW::glew_s
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(GLEW_STATIC_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::glew_s
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::glew_s
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_STATIC_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::glew_s
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::glew_s
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
+ endif()
+endif()
+
+if(NOT TARGET GLEW::GLEW)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::GLEW imported target.")
+ endif()
+
+ add_library(GLEW::GLEW UNKNOWN IMPORTED)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(TARGET GLEW::glew)
+ if(GLEW_SHARED_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_SHARED_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
endif()
- if(GLEW_LIBRARY_DEBUG)
- set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
- set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_LIBRARY_DEBUG}")
+ elseif(TARGET GLEW::glew_s)
+ if(GLEW_STATIC_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
endif()
- if(NOT GLEW_LIBRARY_RELEASE AND NOT GLEW_LIBRARY_DEBUG)
- set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_LOCATION "${GLEW_LIBRARY}")
+ if(GLEW_STATIC_LIBRARY_DEBUG AND GLEW_USE_STATIC_LIBS)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
endif()
+
+ elseif(GLEW_VERBOSE)
+ message(WARNING "FindGLEW: no `GLEW::glew` or `GLEW::glew_s` target was created. Something went wrong in FindGLEW target creation.")
endif()
endif()
-
-mark_as_advanced(GLEW_INCLUDE_DIR)
diff --git a/Modules/FindGLU.cmake b/Modules/FindGLU.cmake
index dbec6d1cb..98928059c 100644
--- a/Modules/FindGLU.cmake
+++ b/Modules/FindGLU.cmake
@@ -15,4 +15,3 @@ if (OPENGL_GLU_FOUND)
set (GLU_LIBRARY ${OPENGL_LIBRARIES})
set (GLU_INCLUDE_PATH ${OPENGL_INCLUDE_DIR})
endif ()
-
diff --git a/Modules/FindGLUT.cmake b/Modules/FindGLUT.cmake
index d42db539f..a22bf5bca 100644
--- a/Modules/FindGLUT.cmake
+++ b/Modules/FindGLUT.cmake
@@ -5,7 +5,7 @@
FindGLUT
--------
-try to find glut library and include files.
+Find OpenGL Utility Toolkit (GLUT) library and include files.
IMPORTED Targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindGSL.cmake b/Modules/FindGSL.cmake
index db0512166..da1b3c4e4 100644
--- a/Modules/FindGSL.cmake
+++ b/Modules/FindGSL.cmake
@@ -5,7 +5,7 @@
FindGSL
--------
-Find the native GSL includes and libraries.
+Find the native GNU Scientific Library (GSL) includes and libraries.
The GNU Scientific Library (GSL) is a numerical library for C and C++
programmers. It is free software under the GNU General Public
diff --git a/Modules/FindGTK.cmake b/Modules/FindGTK.cmake
index 8cc6c970d..552b19a5f 100644
--- a/Modules/FindGTK.cmake
+++ b/Modules/FindGTK.cmake
@@ -5,7 +5,7 @@
FindGTK
-------
-try to find GTK (and glib) and GTKGLArea
+Find GTK, glib and GTKGLArea
::
@@ -151,6 +151,3 @@ if(UNIX)
)
endif()
-
-
-
diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake
index 6c1897cae..e3af6766f 100644
--- a/Modules/FindGTK2.cmake
+++ b/Modules/FindGTK2.cmake
@@ -5,10 +5,8 @@
FindGTK2
--------
-FindGTK2.cmake
-
-This module can find the GTK2 widget libraries and several of its
-other optional components like gtkmm, glade, and glademm.
+Find the GTK2 widget libraries and several of its
+other optional components like ``gtkmm``, ``glade``, and ``glademm``.
NOTE: If you intend to use version checking, CMake 2.6.2 or later is
@@ -303,9 +301,7 @@ function(_GTK2_FIND_INCLUDE_DIR _var _hdr)
/opt/gnome/lib
/opt/openwin/include
/usr/openwin/lib
- /sw/include
/sw/lib
- /opt/local/include
/opt/local/lib
/usr/pkg/lib
/usr/pkg/include/glib
@@ -415,7 +411,6 @@ function(_GTK2_FIND_LIBRARY _var _lib _expand_vc _append_version)
PATHS
/opt/gnome/lib
/usr/openwin/lib
- /sw/lib
$ENV{GTKMM_BASEPATH}/lib
[HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/lib
[HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/lib
@@ -952,5 +947,5 @@ else()
endif()
if(GTK2_INCLUDE_DIRS)
- list(REMOVE_DUPLICATES GTK2_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES GTK2_INCLUDE_DIRS)
endif()
diff --git a/Modules/FindGettext.cmake b/Modules/FindGettext.cmake
index 9e29e8d2d..213ad13de 100644
--- a/Modules/FindGettext.cmake
+++ b/Modules/FindGettext.cmake
@@ -63,18 +63,18 @@ find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
if(GETTEXT_MSGMERGE_EXECUTABLE)
- execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
+ execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
OUTPUT_VARIABLE gettext_version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
- get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
- get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
- if (gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
- set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
- endif()
- unset(gettext_version)
- unset(msgmerge_name)
- unset(msgmerge_namewe)
+ get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
+ get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
+ if (gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
+ set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
+ endif()
+ unset(gettext_version)
+ unset(msgmerge_name)
+ unset(msgmerge_namewe)
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
@@ -83,150 +83,150 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext
VERSION_VAR GETTEXT_VERSION_STRING)
function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
- set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
- get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
- if(NOT currentCounter)
- set(currentCounter 1)
- endif()
- set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
- math(EXPR currentCounter "${currentCounter} + 1")
- set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
+ set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
+ get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
+ if(NOT currentCounter)
+ set(currentCounter 1)
+ endif()
+ set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
+ math(EXPR currentCounter "${currentCounter} + 1")
+ set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()
macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg)
- # make it a real variable, so we can modify it here
- set(_firstPoFile "${_firstPoFileArg}")
-
- set(_gmoFiles)
- get_filename_component(_potName ${_potFile} NAME)
- string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
- get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
-
- set(_addToAll)
- if(${_firstPoFile} STREQUAL "ALL")
- set(_addToAll "ALL")
- set(_firstPoFile)
- endif()
-
- foreach (_currentPoFile ${_firstPoFile} ${ARGN})
- get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
- get_filename_component(_abs_PATH ${_absFile} PATH)
- get_filename_component(_lang ${_absFile} NAME_WE)
- set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
-
- add_custom_command(
- OUTPUT ${_gmoFile}
- COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
- COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
- DEPENDS ${_absPotFile} ${_absFile}
- )
-
- install(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
- set(_gmoFiles ${_gmoFiles} ${_gmoFile})
-
- endforeach ()
-
- if(NOT TARGET translations)
- add_custom_target(translations)
- endif()
+ # make it a real variable, so we can modify it here
+ set(_firstPoFile "${_firstPoFileArg}")
+
+ set(_gmoFiles)
+ get_filename_component(_potName ${_potFile} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
+ get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
+
+ set(_addToAll)
+ if(${_firstPoFile} STREQUAL "ALL")
+ set(_addToAll "ALL")
+ set(_firstPoFile)
+ endif()
+
+ foreach (_currentPoFile ${_firstPoFile} ${ARGN})
+ get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
+ get_filename_component(_abs_PATH ${_absFile} PATH)
+ get_filename_component(_lang ${_absFile} NAME_WE)
+ set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
+
+ add_custom_command(
+ OUTPUT ${_gmoFile}
+ COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
+ DEPENDS ${_absPotFile} ${_absFile}
+ )
+
+ install(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
+ set(_gmoFiles ${_gmoFiles} ${_gmoFile})
+
+ endforeach ()
+
+ if(NOT TARGET translations)
+ add_custom_target(translations)
+ endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName)
- add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
+ add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
- add_dependencies(translations ${uniqueTargetName})
+ add_dependencies(translations ${uniqueTargetName})
endmacro()
function(GETTEXT_PROCESS_POT_FILE _potFile)
- set(_gmoFiles)
- set(_options ALL)
- set(_oneValueArgs INSTALL_DESTINATION)
- set(_multiValueArgs LANGUAGES)
-
- CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
-
- get_filename_component(_potName ${_potFile} NAME)
- string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
- get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
-
- foreach (_lang ${_parsedArguments_LANGUAGES})
- set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
- set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
-
- add_custom_command(
- OUTPUT "${_poFile}"
- COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
- DEPENDS ${_absPotFile}
- )
-
- add_custom_command(
- OUTPUT "${_gmoFile}"
- COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
- DEPENDS ${_absPotFile} ${_poFile}
- )
-
- if(_parsedArguments_INSTALL_DESTINATION)
- install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
- endif()
- list(APPEND _gmoFiles ${_gmoFile})
- endforeach ()
+ set(_gmoFiles)
+ set(_options ALL)
+ set(_oneValueArgs INSTALL_DESTINATION)
+ set(_multiValueArgs LANGUAGES)
+
+ CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+
+ get_filename_component(_potName ${_potFile} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
+ get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
+
+ foreach (_lang ${_parsedArguments_LANGUAGES})
+ set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
+ set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
+
+ add_custom_command(
+ OUTPUT "${_poFile}"
+ COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
+ DEPENDS ${_absPotFile}
+ )
+
+ add_custom_command(
+ OUTPUT "${_gmoFile}"
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
+ DEPENDS ${_absPotFile} ${_poFile}
+ )
+
+ if(_parsedArguments_INSTALL_DESTINATION)
+ install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
+ endif()
+ list(APPEND _gmoFiles ${_gmoFile})
+ endforeach ()
if(NOT TARGET potfiles)
- add_custom_target(potfiles)
+ add_custom_target(potfiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName)
- if(_parsedArguments_ALL)
- add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
- else()
- add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
- endif()
+ if(_parsedArguments_ALL)
+ add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
+ else()
+ add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
+ endif()
- add_dependencies(potfiles ${uniqueTargetName})
+ add_dependencies(potfiles ${uniqueTargetName})
endfunction()
function(GETTEXT_PROCESS_PO_FILES _lang)
- set(_options ALL)
- set(_oneValueArgs INSTALL_DESTINATION)
- set(_multiValueArgs PO_FILES)
- set(_gmoFiles)
-
- CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
-
- foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
- get_filename_component(_name ${_current_PO_FILE} NAME)
- string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
- set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
- add_custom_command(OUTPUT ${_gmoFile}
- COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- DEPENDS ${_current_PO_FILE}
- )
-
- if(_parsedArguments_INSTALL_DESTINATION)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
- endif()
- list(APPEND _gmoFiles ${_gmoFile})
- endforeach()
+ set(_options ALL)
+ set(_oneValueArgs INSTALL_DESTINATION)
+ set(_multiValueArgs PO_FILES)
+ set(_gmoFiles)
+
+ CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+
+ foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
+ get_filename_component(_name ${_current_PO_FILE} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
+ set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
+ add_custom_command(OUTPUT ${_gmoFile}
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ DEPENDS ${_current_PO_FILE}
+ )
+
+ if(_parsedArguments_INSTALL_DESTINATION)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
+ endif()
+ list(APPEND _gmoFiles ${_gmoFile})
+ endforeach()
if(NOT TARGET pofiles)
- add_custom_target(pofiles)
+ add_custom_target(pofiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName)
- if(_parsedArguments_ALL)
- add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
- else()
- add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
- endif()
+ if(_parsedArguments_ALL)
+ add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
+ else()
+ add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
+ endif()
- add_dependencies(pofiles ${uniqueTargetName})
+ add_dependencies(pofiles ${uniqueTargetName})
endfunction()
diff --git a/Modules/FindGnuTLS.cmake b/Modules/FindGnuTLS.cmake
index 9c0744415..123a0f5d5 100644
--- a/Modules/FindGnuTLS.cmake
+++ b/Modules/FindGnuTLS.cmake
@@ -5,7 +5,7 @@
FindGnuTLS
----------
-Try to find the GNU Transport Layer Security library (gnutls)
+Find the GNU Transport Layer Security library (gnutls)
@@ -23,31 +23,31 @@ Once done this will define
if (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARY)
- # in cache already
- set(gnutls_FIND_QUIETLY TRUE)
+ # in cache already
+ set(gnutls_FIND_QUIETLY TRUE)
endif ()
if (NOT WIN32)
- # try using pkg-config to get the directories and then use these values
- # in the find_path() and find_library() calls
- # also fills in GNUTLS_DEFINITIONS, although that isn't normally useful
- find_package(PkgConfig QUIET)
- PKG_CHECK_MODULES(PC_GNUTLS QUIET gnutls)
- set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER})
- set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION})
+ # try using pkg-config to get the directories and then use these values
+ # in the find_path() and find_library() calls
+ # also fills in GNUTLS_DEFINITIONS, although that isn't normally useful
+ find_package(PkgConfig QUIET)
+ PKG_CHECK_MODULES(PC_GNUTLS QUIET gnutls)
+ set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER})
+ set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION})
endif ()
find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h
- HINTS
- ${PC_GNUTLS_INCLUDEDIR}
- ${PC_GNUTLS_INCLUDE_DIRS}
- )
+ HINTS
+ ${PC_GNUTLS_INCLUDEDIR}
+ ${PC_GNUTLS_INCLUDE_DIRS}
+ )
find_library(GNUTLS_LIBRARY NAMES gnutls libgnutls
- HINTS
- ${PC_GNUTLS_LIBDIR}
- ${PC_GNUTLS_LIBRARY_DIRS}
- )
+ HINTS
+ ${PC_GNUTLS_LIBDIR}
+ ${PC_GNUTLS_LIBRARY_DIRS}
+ )
mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY)
@@ -57,6 +57,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GnuTLS
VERSION_VAR GNUTLS_VERSION_STRING)
if(GNUTLS_FOUND)
- set(GNUTLS_LIBRARIES ${GNUTLS_LIBRARY})
- set(GNUTLS_INCLUDE_DIRS ${GNUTLS_INCLUDE_DIR})
+ set(GNUTLS_LIBRARIES ${GNUTLS_LIBRARY})
+ set(GNUTLS_INCLUDE_DIRS ${GNUTLS_INCLUDE_DIR})
endif()
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index 70bfc96f1..08863c867 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -5,43 +5,44 @@
FindHDF5
--------
-Find HDF5, a library for reading and writing self describing array data.
+Find Hierarchical Data Format (HDF5), a library for reading and writing
+self describing array data.
-This module invokes the HDF5 wrapper compiler that should be installed
-alongside HDF5. Depending upon the HDF5 Configuration, the wrapper
-compiler is called either h5cc or h5pcc. If this succeeds, the module
-will then call the compiler with the -show argument to see what flags
-are used when compiling an HDF5 client application.
+This module invokes the ``HDF5`` wrapper compiler that should be installed
+alongside ``HDF5``. Depending upon the ``HDF5`` Configuration, the wrapper
+compiler is called either ``h5cc`` or ``h5pcc``. If this succeeds, the module
+will then call the compiler with the show argument to see what flags
+are used when compiling an ``HDF5`` client application.
-The module will optionally accept the COMPONENTS argument. If no
-COMPONENTS are specified, then the find module will default to finding
-only the HDF5 C library. If one or more COMPONENTS are specified, the
+The module will optionally accept the ``COMPONENTS`` argument. If no
+``COMPONENTS`` are specified, then the find module will default to finding
+only the ``HDF5`` C library. If one or more ``COMPONENTS`` are specified, the
module will attempt to find the language bindings for the specified
-components. The only valid components are C, CXX, Fortran, HL, and
-Fortran_HL. If the COMPONENTS argument is not given, the module will
+components. The only valid components are ``C``, ``CXX``, ``Fortran``, ``HL``,
+and ``Fortran_HL``. If the ``COMPONENTS`` argument is not given, the module will
attempt to find only the C bindings.
This module will read the variable
-HDF5_USE_STATIC_LIBRARIES to determine whether or not to prefer a
-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
+``HDF5_USE_STATIC_LIBRARIES`` to determine whether or not to prefer a
+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.
-To provide the module with a hint about where to find your HDF5
-installation, you can set the environment variable HDF5_ROOT. The
-Find module will then look in this path when searching for HDF5
+To provide the module with a hint about where to find your ``HDF5``
+installation, you can set the environment variable ``HDF5_ROOT``. The
+Find module will then look in this path when searching for ``HDF5``
executables, paths, and libraries.
-Both the serial and parallel HDF5 wrappers are considered and the first
+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
-behavior can be reversed by setting the variable HDF5_PREFER_PARALLEL to
-true.
+behavior can be reversed by setting the variable ``HDF5_PREFER_PARALLEL`` to
+``True``.
In addition to finding the includes and libraries required to compile
-an HDF5 client application, this module also makes an effort to find
-tools that come with the HDF5 distribution that may be useful for
+an ``HDF5`` client application, this module also makes an effort to find
+tools that come with the ``HDF5`` distribution that may be useful for
regression testing.
Result Variables
diff --git a/Modules/FindHSPELL.cmake b/Modules/FindHSPELL.cmake
index ec077a5d0..9724d2cf1 100644
--- a/Modules/FindHSPELL.cmake
+++ b/Modules/FindHSPELL.cmake
@@ -5,7 +5,7 @@
FindHSPELL
----------
-Try to find Hspell
+Try to find Hebrew spell-checker (Hspell) and morphology engine.
Once done this will define
diff --git a/Modules/FindICU.cmake b/Modules/FindICU.cmake
index e4b4909b5..38081f5fa 100644
--- a/Modules/FindICU.cmake
+++ b/Modules/FindICU.cmake
@@ -162,7 +162,8 @@ function(_ICU_FIND)
string(TOUPPER "${program}" program_upcase)
set(cache_var "ICU_${program_upcase}_EXECUTABLE")
set(program_var "ICU_${program_upcase}_EXECUTABLE")
- find_program("${cache_var}" "${program}"
+ find_program("${cache_var}"
+ NAMES "${program}"
HINTS ${icu_roots}
PATH_SUFFIXES ${icu_binary_suffixes}
DOC "ICU ${program} executable"
@@ -228,13 +229,15 @@ function(_ICU_FIND)
list(APPEND component_libnames ${static_component_libnames})
list(APPEND component_debug_libnames ${static_component_debug_libnames})
endif()
- find_library("${component_cache_release}" ${component_libnames}
+ find_library("${component_cache_release}"
+ NAMES ${component_libnames}
HINTS ${icu_roots}
PATH_SUFFIXES ${icu_library_suffixes}
DOC "ICU ${component} library (release)"
NO_PACKAGE_ROOT_PATH
)
- find_library("${component_cache_debug}" ${component_debug_libnames}
+ find_library("${component_cache_debug}"
+ NAMES ${component_debug_libnames}
HINTS ${icu_roots}
PATH_SUFFIXES ${icu_library_suffixes}
DOC "ICU ${component} library (debug)"
@@ -286,7 +289,8 @@ function(_ICU_FIND)
string(REPLACE "." "_" data_upcase "${data_upcase}")
set(cache_var "ICU_${data_upcase}")
set(data_var "ICU_${data_upcase}")
- find_file("${cache_var}" "${data}"
+ find_file("${cache_var}"
+ NAMES "${data}"
HINTS ${icu_roots}
PATH_SUFFIXES ${icu_data_suffixes}
DOC "ICU ${data} data file")
diff --git a/Modules/FindIce.cmake b/Modules/FindIce.cmake
index 1e0f0b828..5ce2b42d9 100644
--- a/Modules/FindIce.cmake
+++ b/Modules/FindIce.cmake
@@ -259,7 +259,7 @@ function(_Ice_FIND)
endif()
unset(vcvers)
- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
if(MSVC_TOOLSET_VERSION GREATER_EQUAL 141)
set(vcvers "141;140")
elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 100)
@@ -435,7 +435,7 @@ function(_Ice_FIND)
set(component_library "${component}")
unset(component_library_release_names)
unset(component_library_debug_names)
- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
string(REGEX MATCH ".+\\+\\+11$" component_library_cpp11 "${component_library}")
if(component_library_cpp11)
string(REGEX REPLACE "^(.+)(\\+\\+11)$" "\\1" component_library "${component_library}")
diff --git a/Modules/FindIcotool.cmake b/Modules/FindIcotool.cmake
index 32fc4aebd..d19c14579 100644
--- a/Modules/FindIcotool.cmake
+++ b/Modules/FindIcotool.cmake
@@ -7,8 +7,8 @@ FindIcotool
Find icotool
-This module looks for icotool. This module defines the following
-values:
+This module looks for icotool. Convert and create Win32 icon and cursor files.
+This module defines the following values:
::
diff --git a/Modules/FindImageMagick.cmake b/Modules/FindImageMagick.cmake
index 2ddd11c8d..8bf5123b7 100644
--- a/Modules/FindImageMagick.cmake
+++ b/Modules/FindImageMagick.cmake
@@ -5,11 +5,11 @@
FindImageMagick
---------------
-Find the ImageMagick binary suite.
+Find ImageMagick binary suite.
This module will search for a set of ImageMagick tools specified as
-components in the FIND_PACKAGE call. Typical components include, but
-are not limited to (future versions of ImageMagick might have
+components in the :command:`find_package` call. Typical components include,
+but are not limited to (future versions of ImageMagick might have
additional components not listed here):
::
@@ -28,7 +28,7 @@ additional components not listed here):
-If no component is specified in the FIND_PACKAGE call, then it only
+If no component is specified in the :command:`find_package` call, then it only
searches for the ImageMagick executable directory. This code defines
the following variables:
@@ -43,7 +43,7 @@ the following variables:
-ImageMagick_VERSION_STRING will not work for old versions like 5.2.3.
+``ImageMagick_VERSION_STRING`` will not work for old versions like 5.2.3.
There are also components for the following ImageMagick APIs:
@@ -80,8 +80,8 @@ Example Usages:
-Note that the standard FIND_PACKAGE features are supported (i.e.,
-QUIET, REQUIRED, etc.).
+Note that the standard :command:`find_package` features are supported (i.e.,
+``QUIET``, ``REQUIRED``, etc.).
#]=======================================================================]
find_package(PkgConfig QUIET)
diff --git a/Modules/FindJPEG.cmake b/Modules/FindJPEG.cmake
index f50f79e9b..0bb698979 100644
--- a/Modules/FindJPEG.cmake
+++ b/Modules/FindJPEG.cmake
@@ -5,7 +5,7 @@
FindJPEG
--------
-Find the JPEG library (libjpeg)
+Find the Joint Photographic Experts Group (JPEG) library (``libjpeg``)
Imported targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindJasper.cmake b/Modules/FindJasper.cmake
index dd0e98411..729a50350 100644
--- a/Modules/FindJasper.cmake
+++ b/Modules/FindJasper.cmake
@@ -41,7 +41,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jasper
VERSION_VAR JASPER_VERSION_STRING)
if (JASPER_FOUND)
- set(JASPER_LIBRARIES ${JASPER_LIBRARIES} ${JPEG_LIBRARIES} )
+ set(JASPER_LIBRARIES ${JASPER_LIBRARIES} ${JPEG_LIBRARIES} )
endif ()
mark_as_advanced(JASPER_INCLUDE_DIR)
diff --git a/Modules/FindKDE3.cmake b/Modules/FindKDE3.cmake
index c7ad6e180..30ea5e62f 100644
--- a/Modules/FindKDE3.cmake
+++ b/Modules/FindKDE3.cmake
@@ -35,7 +35,7 @@ The following user adjustable options are provided:
``KDE3_BUILD_TESTS``
enable this to build KDE testcases
-It also adds the following macros (from KDE3Macros.cmake) SRCS_VAR is
+It also adds the following macros (from ``KDE3Macros.cmake``) ``SRCS_VAR`` is
always the variable which contains the list of source files for your
application or library.
@@ -139,7 +139,7 @@ Author: Alexander Neundorf <neundorf@kde.org>
#]=======================================================================]
if(NOT UNIX AND KDE3_FIND_REQUIRED)
- message(FATAL_ERROR "Compiling KDE3 applications and libraries under Windows is not supported")
+ message(FATAL_ERROR "Compiling KDE3 applications and libraries under Windows is not supported")
endif()
# If Qt4 has already been found, fail.
@@ -170,24 +170,24 @@ find_package(X11 ${_REQ_STRING_KDE3})
#now try to find some kde stuff
find_program(KDECONFIG_EXECUTABLE NAMES kde-config
HINTS
- $ENV{KDEDIR}/bin
- PATHS
- /opt/kde3/bin
- /opt/kde/bin
+ $ENV{KDEDIR}/bin
+ PATHS
+ /opt/kde3/bin
+ /opt/kde/bin
)
set(KDE3PREFIX)
if(KDECONFIG_EXECUTABLE)
- execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --version
- OUTPUT_VARIABLE kde_config_version )
+ execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --version
+ OUTPUT_VARIABLE kde_config_version )
- string(REGEX MATCH "KDE: .\\." kde_version "${kde_config_version}")
- if ("${kde_version}" MATCHES "KDE: 3\\.")
- execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --prefix
- OUTPUT_VARIABLE kdedir )
- string(REPLACE "\n" "" KDE3PREFIX "${kdedir}")
+ string(REGEX MATCH "KDE: .\\." kde_version "${kde_config_version}")
+ if ("${kde_version}" MATCHES "KDE: 3\\.")
+ execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --prefix
+ OUTPUT_VARIABLE kdedir )
+ string(REPLACE "\n" "" KDE3PREFIX "${kdedir}")
- endif ()
+ endif ()
endif()
@@ -196,22 +196,22 @@ endif()
# kpassdlg.h comes from kdeui and doesn't exist in KDE4 anymore
find_path(KDE3_INCLUDE_DIR kpassdlg.h
HINTS
- $ENV{KDEDIR}/include
- ${KDE3PREFIX}/include
+ $ENV{KDEDIR}/include
+ ${KDE3PREFIX}/include
PATHS
- /opt/kde3/include
- /opt/kde/include
+ /opt/kde3/include
+ /opt/kde/include
PATH_SUFFIXES include/kde
)
#now the KDE library directory
find_library(KDE3_KDECORE_LIBRARY NAMES kdecore
HINTS
- $ENV{KDEDIR}/lib
- ${KDE3PREFIX}/lib
+ $ENV{KDEDIR}/lib
+ ${KDE3PREFIX}/lib
PATHS
- /opt/kde3/lib
- /opt/kde/lib
+ /opt/kde3/lib
+ /opt/kde/lib
)
set(QT_AND_KDECORE_LIBS ${QT_LIBRARIES} ${KDE3_KDECORE_LIBRARY})
@@ -219,49 +219,49 @@ set(QT_AND_KDECORE_LIBS ${QT_LIBRARIES} ${KDE3_KDECORE_LIBRARY})
get_filename_component(KDE3_LIB_DIR ${KDE3_KDECORE_LIBRARY} PATH )
if(NOT KDE3_LIBTOOL_DIR)
- if(KDE3_KDECORE_LIBRARY MATCHES lib64)
- set(KDE3_LIBTOOL_DIR /lib64/kde3)
- elseif(KDE3_KDECORE_LIBRARY MATCHES libx32)
- set(KDE3_LIBTOOL_DIR /libx32/kde3)
- else()
- set(KDE3_LIBTOOL_DIR /lib/kde3)
- endif()
+ if(KDE3_KDECORE_LIBRARY MATCHES lib64)
+ set(KDE3_LIBTOOL_DIR /lib64/kde3)
+ elseif(KDE3_KDECORE_LIBRARY MATCHES libx32)
+ set(KDE3_LIBTOOL_DIR /libx32/kde3)
+ else()
+ set(KDE3_LIBTOOL_DIR /lib/kde3)
+ endif()
endif()
#now search for the dcop utilities
find_program(KDE3_DCOPIDL_EXECUTABLE NAMES dcopidl
HINTS
- $ENV{KDEDIR}/bin
- ${KDE3PREFIX}/bin
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
PATHS
- /opt/kde3/bin
- /opt/kde/bin
+ /opt/kde3/bin
+ /opt/kde/bin
)
find_program(KDE3_DCOPIDL2CPP_EXECUTABLE NAMES dcopidl2cpp
HINTS
- $ENV{KDEDIR}/bin
- ${KDE3PREFIX}/bin
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
PATHS
- /opt/kde3/bin
- /opt/kde/bin
+ /opt/kde3/bin
+ /opt/kde/bin
)
find_program(KDE3_KCFGC_EXECUTABLE NAMES kconfig_compiler
HINTS
- $ENV{KDEDIR}/bin
- ${KDE3PREFIX}/bin
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
PATHS
- /opt/kde3/bin
- /opt/kde/bin
+ /opt/kde3/bin
+ /opt/kde/bin
)
#SET KDE3_FOUND
if (KDE3_INCLUDE_DIR AND KDE3_LIB_DIR AND KDE3_DCOPIDL_EXECUTABLE AND KDE3_DCOPIDL2CPP_EXECUTABLE AND KDE3_KCFGC_EXECUTABLE)
- set(KDE3_FOUND TRUE)
+ set(KDE3_FOUND TRUE)
else ()
- set(KDE3_FOUND FALSE)
+ set(KDE3_FOUND FALSE)
endif ()
# add some KDE specific stuff
@@ -269,36 +269,36 @@ set(KDE3_DEFINITIONS -DQT_CLEAN_NAMESPACE -D_GNU_SOURCE)
# set compiler flags only if KDE3 has actually been found
if(KDE3_FOUND)
- set(_KDE3_USE_FLAGS FALSE)
- if(CMAKE_COMPILER_IS_GNUCXX)
- set(_KDE3_USE_FLAGS TRUE) # use flags for gnu compiler
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
- OUTPUT_VARIABLE out)
- # gnu gcc 2.96 does not work with flags
- # I guess 2.95 also doesn't then
- if("${out}" MATCHES "2.9[56]")
- set(_KDE3_USE_FLAGS FALSE)
- endif()
- endif()
-
- #only on linux, but NOT e.g. on FreeBSD:
- if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND _KDE3_USE_FLAGS)
- set (KDE3_DEFINITIONS ${KDE3_DEFINITIONS} -D_XOPEN_SOURCE=500 -D_BSD_SOURCE)
- set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
- set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-exceptions -fno-check-new -fno-common")
- endif()
-
- # works on FreeBSD, NOT tested on NetBSD and OpenBSD
- if (CMAKE_SYSTEM_NAME MATCHES BSD AND _KDE3_USE_FLAGS)
- set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
- set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-exceptions -fno-check-new -fno-common")
- endif ()
-
- # if no special buildtype is selected, add -O2 as default optimization
- if (NOT CMAKE_BUILD_TYPE AND _KDE3_USE_FLAGS)
- set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
- set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
- endif ()
+ set(_KDE3_USE_FLAGS FALSE)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(_KDE3_USE_FLAGS TRUE) # use flags for gnu compiler
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
+ OUTPUT_VARIABLE out)
+ # gnu gcc 2.96 does not work with flags
+ # I guess 2.95 also doesn't then
+ if("${out}" MATCHES "2.9[56]")
+ set(_KDE3_USE_FLAGS FALSE)
+ endif()
+ endif()
+
+ #only on linux, but NOT e.g. on FreeBSD:
+ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND _KDE3_USE_FLAGS)
+ set (KDE3_DEFINITIONS ${KDE3_DEFINITIONS} -D_XOPEN_SOURCE=500 -D_BSD_SOURCE)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-exceptions -fno-check-new -fno-common")
+ endif()
+
+ # works on FreeBSD, NOT tested on NetBSD and OpenBSD
+ if (CMAKE_SYSTEM_NAME MATCHES BSD AND _KDE3_USE_FLAGS)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-exceptions -fno-check-new -fno-common")
+ endif ()
+
+ # if no special buildtype is selected, add -O2 as default optimization
+ if (NOT CMAKE_BUILD_TYPE AND _KDE3_USE_FLAGS)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+ endif ()
#set(CMAKE_SHARED_LINKER_FLAGS "-avoid-version -module -Wl,--no-undefined -Wl,--allow-shlib-undefined")
#set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -avoid-version -Wl,--no-undefined -lc")
@@ -311,51 +311,50 @@ include(${CMAKE_CURRENT_LIST_DIR}/KDE3Macros.cmake)
macro (KDE3_PRINT_RESULTS)
- if(KDE3_INCLUDE_DIR)
- message(STATUS "Found KDE3 include dir: ${KDE3_INCLUDE_DIR}")
- else()
- message(STATUS "Didn't find KDE3 headers")
- endif()
-
- if(KDE3_LIB_DIR)
- message(STATUS "Found KDE3 library dir: ${KDE3_LIB_DIR}")
- else()
- message(STATUS "Didn't find KDE3 core library")
- endif()
-
- if(KDE3_DCOPIDL_EXECUTABLE)
- message(STATUS "Found KDE3 dcopidl preprocessor: ${KDE3_DCOPIDL_EXECUTABLE}")
- else()
- message(STATUS "Didn't find the KDE3 dcopidl preprocessor")
- endif()
-
- if(KDE3_DCOPIDL2CPP_EXECUTABLE)
- message(STATUS "Found KDE3 dcopidl2cpp preprocessor: ${KDE3_DCOPIDL2CPP_EXECUTABLE}")
- else()
- message(STATUS "Didn't find the KDE3 dcopidl2cpp preprocessor")
- endif()
-
- if(KDE3_KCFGC_EXECUTABLE)
- message(STATUS "Found KDE3 kconfig_compiler preprocessor: ${KDE3_KCFGC_EXECUTABLE}")
- else()
- message(STATUS "Didn't find the KDE3 kconfig_compiler preprocessor")
- endif()
+ if(KDE3_INCLUDE_DIR)
+ message(STATUS "Found KDE3 include dir: ${KDE3_INCLUDE_DIR}")
+ else()
+ message(STATUS "Didn't find KDE3 headers")
+ endif()
+
+ if(KDE3_LIB_DIR)
+ message(STATUS "Found KDE3 library dir: ${KDE3_LIB_DIR}")
+ else()
+ message(STATUS "Didn't find KDE3 core library")
+ endif()
+
+ if(KDE3_DCOPIDL_EXECUTABLE)
+ message(STATUS "Found KDE3 dcopidl preprocessor: ${KDE3_DCOPIDL_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 dcopidl preprocessor")
+ endif()
+
+ if(KDE3_DCOPIDL2CPP_EXECUTABLE)
+ message(STATUS "Found KDE3 dcopidl2cpp preprocessor: ${KDE3_DCOPIDL2CPP_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 dcopidl2cpp preprocessor")
+ endif()
+
+ if(KDE3_KCFGC_EXECUTABLE)
+ message(STATUS "Found KDE3 kconfig_compiler preprocessor: ${KDE3_KCFGC_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 kconfig_compiler preprocessor")
+ endif()
endmacro ()
if (KDE3_FIND_REQUIRED AND NOT KDE3_FOUND)
- #bail out if something wasn't found
- KDE3_PRINT_RESULTS()
- message(FATAL_ERROR "Could NOT find everything required for compiling KDE 3 programs")
+ #bail out if something wasn't found
+ KDE3_PRINT_RESULTS()
+ message(FATAL_ERROR "Could NOT find everything required for compiling KDE 3 programs")
endif ()
if (NOT KDE3_FIND_QUIETLY)
- KDE3_PRINT_RESULTS()
+ KDE3_PRINT_RESULTS()
endif ()
#add the found Qt and KDE include directories to the current include path
set(KDE3_INCLUDE_DIRS ${QT_INCLUDE_DIR} ${KDE3_INCLUDE_DIR})
-
diff --git a/Modules/FindKDE4.cmake b/Modules/FindKDE4.cmake
index c04804be9..695e9ac90 100644
--- a/Modules/FindKDE4.cmake
+++ b/Modules/FindKDE4.cmake
@@ -19,7 +19,7 @@ the given order:
-Please look in FindKDE4Internal.cmake and KDE4Macros.cmake for more
+Please look in ``FindKDE4Internal.cmake`` and ``KDE4Macros.cmake`` for more
information. They are installed with the KDE 4 libraries in
$KDEDIRS/share/apps/cmake/modules/.
@@ -57,47 +57,47 @@ find_program(KDE4_KDECONFIG_EXECUTABLE NAMES kde4-config
)
if (NOT KDE4_KDECONFIG_EXECUTABLE)
- if (KDE4_FIND_REQUIRED)
- message(FATAL_ERROR "ERROR: Could not find KDE4 kde4-config")
- endif ()
+ if (KDE4_FIND_REQUIRED)
+ message(FATAL_ERROR "ERROR: Could not find KDE4 kde4-config")
+ endif ()
endif ()
# when cross compiling, KDE4_DATA_DIR may be already preset
if(NOT KDE4_DATA_DIR)
- if(CMAKE_CROSSCOMPILING)
- # when cross compiling, don't run kde4-config but use its location as install dir
- get_filename_component(KDE4_DATA_DIR "${KDE4_KDECONFIG_EXECUTABLE}" PATH)
- get_filename_component(KDE4_DATA_DIR "${KDE4_DATA_DIR}" PATH)
- else()
- # then ask kde4-config for the kde data dirs
-
- if(KDE4_KDECONFIG_EXECUTABLE)
- execute_process(COMMAND "${KDE4_KDECONFIG_EXECUTABLE}" --path data OUTPUT_VARIABLE _data_DIR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
- file(TO_CMAKE_PATH "${_data_DIR}" _data_DIR)
- # then check the data dirs for FindKDE4Internal.cmake
- find_path(KDE4_DATA_DIR cmake/modules/FindKDE4Internal.cmake HINTS ${_data_DIR})
- endif()
- endif()
+ if(CMAKE_CROSSCOMPILING)
+ # when cross compiling, don't run kde4-config but use its location as install dir
+ get_filename_component(KDE4_DATA_DIR "${KDE4_KDECONFIG_EXECUTABLE}" PATH)
+ get_filename_component(KDE4_DATA_DIR "${KDE4_DATA_DIR}" PATH)
+ else()
+ # then ask kde4-config for the kde data dirs
+
+ if(KDE4_KDECONFIG_EXECUTABLE)
+ execute_process(COMMAND "${KDE4_KDECONFIG_EXECUTABLE}" --path data OUTPUT_VARIABLE _data_DIR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
+ file(TO_CMAKE_PATH "${_data_DIR}" _data_DIR)
+ # then check the data dirs for FindKDE4Internal.cmake
+ find_path(KDE4_DATA_DIR cmake/modules/FindKDE4Internal.cmake HINTS ${_data_DIR})
+ endif()
+ endif()
endif()
# if it has been found...
if (KDE4_DATA_DIR)
- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${KDE4_DATA_DIR}/cmake/modules)
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${KDE4_DATA_DIR}/cmake/modules)
- if (KDE4_FIND_QUIETLY)
- set(_quiet QUIET)
- endif ()
+ if (KDE4_FIND_QUIETLY)
+ set(_quiet QUIET)
+ endif ()
- if (KDE4_FIND_REQUIRED)
- set(_req REQUIRED)
- endif ()
+ if (KDE4_FIND_REQUIRED)
+ set(_req REQUIRED)
+ endif ()
- # use FindKDE4Internal.cmake to do the rest
- find_package(KDE4Internal ${_req} ${_quiet} NO_POLICY_SCOPE)
+ # use FindKDE4Internal.cmake to do the rest
+ find_package(KDE4Internal ${_req} ${_quiet} NO_POLICY_SCOPE)
else ()
- if (KDE4_FIND_REQUIRED)
- message(FATAL_ERROR "ERROR: cmake/modules/FindKDE4Internal.cmake not found in ${_data_DIR}")
- endif ()
+ if (KDE4_FIND_REQUIRED)
+ message(FATAL_ERROR "ERROR: cmake/modules/FindKDE4Internal.cmake not found in ${_data_DIR}")
+ endif ()
endif ()
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index d6646eaac..c9c3cce42 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -5,13 +5,13 @@
FindLAPACK
----------
-Find LAPACK library
+Find Linear Algebra PACKage (LAPACK) library
This module finds an installed fortran library that implements the
LAPACK linear-algebra interface (see http://www.netlib.org/lapack/).
The approach follows that taken for the autoconf macro file,
-acx_lapack.m4 (distributed at
+``acx_lapack.m4`` (distributed at
http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html).
Input Variables
@@ -173,11 +173,11 @@ if(_libraries_work)
#message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
endif()
- if(_libraries_work)
- set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threads})
- else()
- set(${LIBRARIES} FALSE)
- endif()
+if(_libraries_work)
+ set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threads})
+else()
+ set(${LIBRARIES} FALSE)
+endif()
endmacro()
@@ -325,25 +325,25 @@ if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
endif ()
#acml lapack
- if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
- if (BLAS_LIBRARIES MATCHES ".+acml.+")
- set (LAPACK_LIBRARIES ${BLAS_LIBRARIES})
- endif ()
- endif ()
+if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+ if (BLAS_LIBRARIES MATCHES ".+acml.+")
+ set (LAPACK_LIBRARIES ${BLAS_LIBRARIES})
+ endif ()
+endif ()
# Apple LAPACK library?
if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
- if(NOT LAPACK_LIBRARIES)
- check_lapack_libraries(
- LAPACK_LIBRARIES
- LAPACK
- cheev
- ""
- "Accelerate"
- "${BLAS_LIBRARIES}"
- ""
- )
- endif()
+ if(NOT LAPACK_LIBRARIES)
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "Accelerate"
+ "${BLAS_LIBRARIES}"
+ ""
+ )
+ endif()
endif ()
if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
if ( NOT LAPACK_LIBRARIES )
@@ -380,50 +380,50 @@ else()
endif()
if(BLA_F95)
- if(LAPACK95_LIBRARIES)
- set(LAPACK95_FOUND TRUE)
- else()
- set(LAPACK95_FOUND FALSE)
- endif()
- if(NOT LAPACK_FIND_QUIETLY)
- if(LAPACK95_FOUND)
- message(STATUS "A library with LAPACK95 API found.")
+ if(LAPACK95_LIBRARIES)
+ set(LAPACK95_FOUND TRUE)
else()
- if(LAPACK_FIND_REQUIRED)
- message(FATAL_ERROR
- "A required library with LAPACK95 API not found. Please specify library location."
- )
+ set(LAPACK95_FOUND FALSE)
+ endif()
+ if(NOT LAPACK_FIND_QUIETLY)
+ if(LAPACK95_FOUND)
+ message(STATUS "A library with LAPACK95 API found.")
else()
- message(STATUS
- "A library with LAPACK95 API not found. Please specify library location."
- )
+ if(LAPACK_FIND_REQUIRED)
+ message(FATAL_ERROR
+ "A required library with LAPACK95 API not found. Please specify library location."
+ )
+ else()
+ message(STATUS
+ "A library with LAPACK95 API not found. Please specify library location."
+ )
+ endif()
endif()
endif()
- endif()
- set(LAPACK_FOUND "${LAPACK95_FOUND}")
- set(LAPACK_LIBRARIES "${LAPACK95_LIBRARIES}")
+ set(LAPACK_FOUND "${LAPACK95_FOUND}")
+ set(LAPACK_LIBRARIES "${LAPACK95_LIBRARIES}")
else()
- if(LAPACK_LIBRARIES)
- set(LAPACK_FOUND TRUE)
- else()
- set(LAPACK_FOUND FALSE)
- endif()
-
- if(NOT LAPACK_FIND_QUIETLY)
- if(LAPACK_FOUND)
- message(STATUS "A library with LAPACK API found.")
+ if(LAPACK_LIBRARIES)
+ set(LAPACK_FOUND TRUE)
else()
- if(LAPACK_FIND_REQUIRED)
- message(FATAL_ERROR
- "A required library with LAPACK API not found. Please specify library location."
- )
+ set(LAPACK_FOUND FALSE)
+ endif()
+
+ if(NOT LAPACK_FIND_QUIETLY)
+ if(LAPACK_FOUND)
+ message(STATUS "A library with LAPACK API found.")
else()
- message(STATUS
- "A library with LAPACK API not found. Please specify library location."
- )
+ if(LAPACK_FIND_REQUIRED)
+ message(FATAL_ERROR
+ "A required library with LAPACK API not found. Please specify library location."
+ )
+ else()
+ message(STATUS
+ "A library with LAPACK API not found. Please specify library location."
+ )
+ endif()
endif()
endif()
- endif()
endif()
cmake_pop_check_state()
diff --git a/Modules/FindLATEX.cmake b/Modules/FindLATEX.cmake
index 01f479397..b0dad7da3 100644
--- a/Modules/FindLATEX.cmake
+++ b/Modules/FindLATEX.cmake
@@ -5,9 +5,9 @@
FindLATEX
---------
-Find Latex
+Find LaTeX
-This module finds an installed Latex and determines the location
+This module finds an installed LaTeX and determines the location
of the compiler. Additionally the module looks for Latex-related
software like BibTeX.
@@ -171,7 +171,7 @@ find_program(XINDY_COMPILER
/usr/bin
)
if (XINDY_COMPILER)
- set(LATEX_XINDY_FOUND TRUE)
+ set(LATEX_XINDY_FOUND TRUE)
else()
set(LATEX_XINDY_FOUND FALSE)
endif()
diff --git a/Modules/FindLTTngUST.cmake b/Modules/FindLTTngUST.cmake
index a074187ca..9cd17eb05 100644
--- a/Modules/FindLTTngUST.cmake
+++ b/Modules/FindLTTngUST.cmake
@@ -5,7 +5,8 @@
FindLTTngUST
------------
-This module finds the `LTTng-UST <http://lttng.org/>`__ library.
+Find
+`Linux Trace Toolkit Next Generation (LTTng-UST) <http://lttng.org/>`__ library.
Imported target
^^^^^^^^^^^^^^^
diff --git a/Modules/FindLibArchive.cmake b/Modules/FindLibArchive.cmake
index 34fc2e252..ef27b7dc0 100644
--- a/Modules/FindLibArchive.cmake
+++ b/Modules/FindLibArchive.cmake
@@ -5,7 +5,8 @@
FindLibArchive
--------------
-Find libarchive library and headers
+Find libarchive library and headers.
+Libarchive is multi-format archive and compression library.
The module defines the following variables:
diff --git a/Modules/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
index 622574438..fc9765518 100644
--- a/Modules/FindLibLZMA.cmake
+++ b/Modules/FindLibLZMA.cmake
@@ -59,13 +59,13 @@ endif()
# it can be found in http://tukaani.org/xz/
# Avoid using old codebase
if (LIBLZMA_LIBRARY)
- include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
- set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
- set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY})
- CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_auto_decoder "" LIBLZMA_HAS_AUTO_DECODER)
- CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_easy_encoder "" LIBLZMA_HAS_EASY_ENCODER)
- CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_lzma_preset "" LIBLZMA_HAS_LZMA_PRESET)
- set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+ set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
+ set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY})
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_auto_decoder "" LIBLZMA_HAS_AUTO_DECODER)
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_easy_encoder "" LIBLZMA_HAS_EASY_ENCODER)
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY} lzma_lzma_preset "" LIBLZMA_HAS_LZMA_PRESET)
+ set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
endif ()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
index 47c0e7907..da8bfe0d4 100644
--- a/Modules/FindLibXml2.cmake
+++ b/Modules/FindLibXml2.cmake
@@ -96,7 +96,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2
mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE)
if(LibXml2_FOUND AND NOT TARGET LibXml2::LibXml2)
- add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
- set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}")
- set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}")
+ add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
+ set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}")
+ set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}")
endif()
diff --git a/Modules/FindLibXslt.cmake b/Modules/FindLibXslt.cmake
index 4cca64f2c..01a9d8be3 100644
--- a/Modules/FindLibXslt.cmake
+++ b/Modules/FindLibXslt.cmake
@@ -5,7 +5,8 @@
FindLibXslt
-----------
-Try to find the LibXslt library
+Find the XSL Transformations, Extensible Stylesheet Language
+Transformations (XSLT) library (LibXslt)
Once done this will define
diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake
index eb3b5fb0d..caf9d69b2 100644
--- a/Modules/FindLua.cmake
+++ b/Modules/FindLua.cmake
@@ -7,7 +7,9 @@ FindLua
-Locate Lua library This module defines
+Locate Lua library.
+
+This module defines::
::
@@ -82,105 +84,104 @@ function(_lua_get_versions)
endfunction()
function(_lua_set_version_vars)
- set(_lua_include_subdirs_raw "lua")
-
- foreach (ver IN LISTS _lua_append_versions)
- string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
- list(APPEND _lua_include_subdirs_raw
- lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
- lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
- lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ set(_lua_include_subdirs_raw "lua")
+
+ foreach (ver IN LISTS _lua_append_versions)
+ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
+ list(APPEND _lua_include_subdirs_raw
+ lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+ lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
)
- endforeach ()
+ endforeach ()
- # Prepend "include/" to each path directly after the path
- set(_lua_include_subdirs "include")
- foreach (dir IN LISTS _lua_include_subdirs_raw)
- list(APPEND _lua_include_subdirs "${dir}" "include/${dir}")
- endforeach ()
+ # Prepend "include/" to each path directly after the path
+ set(_lua_include_subdirs "include")
+ foreach (dir IN LISTS _lua_include_subdirs_raw)
+ list(APPEND _lua_include_subdirs "${dir}" "include/${dir}")
+ endforeach ()
- set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
+ set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
endfunction(_lua_set_version_vars)
function(_lua_get_header_version)
- unset(LUA_VERSION_STRING PARENT_SCOPE)
- set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h")
-
- if (NOT EXISTS "${_hdr_file}")
- return()
+ unset(LUA_VERSION_STRING PARENT_SCOPE)
+ set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h")
+
+ if (NOT EXISTS "${_hdr_file}")
+ return()
+ endif ()
+
+ # At least 5.[012] have different ways to express the version
+ # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
+ # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
+ file(STRINGS "${_hdr_file}" lua_version_strings
+ REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
+
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
+ if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
+ set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
+ else ()
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
endif ()
-
- # At least 5.[012] have different ways to express the version
- # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
- # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
- file(STRINGS "${_hdr_file}" lua_version_strings
- REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
-
- string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
- if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
- string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
- string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
- set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
- else ()
- string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
- if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
- string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
- endif ()
- string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
- string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
- string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+ endif ()
+ foreach (ver IN LISTS _lua_append_versions)
+ if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
+ set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE)
+ set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE)
+ set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE)
+ set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE)
+ return()
endif ()
- foreach (ver IN LISTS _lua_append_versions)
- if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
- set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE)
- set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE)
- set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE)
- set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE)
- return()
- endif ()
- endforeach ()
+ endforeach ()
endfunction(_lua_get_header_version)
function(_lua_find_header)
- _lua_set_version_vars()
-
- # Initialize as local variable
- set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH})
- while (TRUE)
- # Find the next header to test. Check each possible subdir in order
- # This prefers e.g. higher versions as they are earlier in the list
- # It is also consistent with previous versions of FindLua
- foreach (subdir IN LISTS _lua_include_subdirs)
- find_path(LUA_INCLUDE_DIR lua.h
- HINTS
- ENV LUA_DIR
- PATH_SUFFIXES ${subdir}
- )
- if (LUA_INCLUDE_DIR)
- break()
- endif()
- endforeach()
- # Did not found header -> Fail
- if (NOT LUA_INCLUDE_DIR)
- return()
- endif()
- _lua_get_header_version()
- # Found accepted version -> Ok
- if (LUA_VERSION_STRING)
- if (LUA_Debug)
- message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h")
- endif()
- return()
- endif()
- # Found wrong version -> Ignore this path and retry
- if (LUA_Debug)
- message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}")
- endif()
- list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}")
- unset(LUA_INCLUDE_DIR CACHE)
- unset(LUA_INCLUDE_DIR)
- unset(LUA_INCLUDE_DIR PARENT_SCOPE)
- endwhile ()
+ _lua_set_version_vars()
+
+ # Initialize as local variable
+ set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH})
+ while (TRUE)
+ # Find the next header to test. Check each possible subdir in order
+ # This prefers e.g. higher versions as they are earlier in the list
+ # It is also consistent with previous versions of FindLua
+ foreach (subdir IN LISTS _lua_include_subdirs)
+ find_path(LUA_INCLUDE_DIR lua.h
+ HINTS ENV LUA_DIR
+ PATH_SUFFIXES ${subdir}
+ )
+ if (LUA_INCLUDE_DIR)
+ break()
+ endif()
+ endforeach()
+ # Did not found header -> Fail
+ if (NOT LUA_INCLUDE_DIR)
+ return()
+ endif()
+ _lua_get_header_version()
+ # Found accepted version -> Ok
+ if (LUA_VERSION_STRING)
+ if (LUA_Debug)
+ message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h")
+ endif()
+ return()
+ endif()
+ # Found wrong version -> Ignore this path and retry
+ if (LUA_Debug)
+ message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}")
+ endif()
+ list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}")
+ unset(LUA_INCLUDE_DIR CACHE)
+ unset(LUA_INCLUDE_DIR)
+ unset(LUA_INCLUDE_DIR PARENT_SCOPE)
+ endwhile ()
endfunction()
_lua_get_versions()
@@ -189,11 +190,11 @@ _lua_get_header_version()
unset(_lua_append_versions)
if (LUA_VERSION_STRING)
- set(_lua_library_names
- lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}
- lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
- lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
- lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ set(_lua_library_names
+ lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}
+ lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
)
endif ()
@@ -207,21 +208,21 @@ find_library(LUA_LIBRARY
unset(_lua_library_names)
if (LUA_LIBRARY)
- # include the math library for Unix
- if (UNIX AND NOT APPLE AND NOT BEOS)
- find_library(LUA_MATH_LIBRARY m)
- set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
-
- # include dl library for statically-linked Lua library
- get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT)
- if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
- list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS})
- endif()
-
- # For Windows and Mac, don't need to explicitly include the math library
- else ()
- set(LUA_LIBRARIES "${LUA_LIBRARY}")
- endif ()
+ # include the math library for Unix
+ if (UNIX AND NOT APPLE AND NOT BEOS)
+ find_library(LUA_MATH_LIBRARY m)
+ set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
+
+ # include dl library for statically-linked Lua library
+ get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT)
+ if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
+ list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS})
+ endif()
+
+ # For Windows and Mac, don't need to explicitly include the math library
+ else ()
+ set(LUA_LIBRARIES "${LUA_LIBRARY}")
+ endif ()
endif ()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
diff --git a/Modules/FindLua50.cmake b/Modules/FindLua50.cmake
index aafc05664..0575caac6 100644
--- a/Modules/FindLua50.cmake
+++ b/Modules/FindLua50.cmake
@@ -7,7 +7,8 @@ FindLua50
-Locate Lua library This module defines
+Locate Lua library.
+This module defines::
::
@@ -40,9 +41,6 @@ find_path(LUA_INCLUDE_DIR lua.h
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw # Fink
- /opt/local # DarwinPorts
- /opt/csw # Blastwave
/opt
)
@@ -54,9 +52,6 @@ find_library(LUA_LIBRARY_lua
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw
- /opt/local
- /opt/csw
/opt
)
@@ -72,9 +67,6 @@ else()
ENV LUA_DIR
PATH_SUFFIXES lib
PATHS
- /sw
- /opt/local
- /opt/csw
/opt
)
if(LUA_LIBRARY_lualib AND LUA_LIBRARY_lua)
@@ -96,4 +88,3 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua50 DEFAULT_MSG LUA_LIBRARIES LUA_INCLUDE_DIR)
mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES)
-
diff --git a/Modules/FindLua51.cmake b/Modules/FindLua51.cmake
index 31eaf87bb..283a3ebfc 100644
--- a/Modules/FindLua51.cmake
+++ b/Modules/FindLua51.cmake
@@ -7,7 +7,8 @@ FindLua51
-Locate Lua library This module defines
+Locate Lua library.
+This module defines::
::
@@ -41,9 +42,6 @@ find_path(LUA_INCLUDE_DIR lua.h
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw # Fink
- /opt/local # DarwinPorts
- /opt/csw # Blastwave
/opt
)
@@ -55,9 +53,6 @@ find_library(LUA_LIBRARY
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw
- /opt/local
- /opt/csw
/opt
)
@@ -87,4 +82,3 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua51
VERSION_VAR LUA_VERSION_STRING)
mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)
-
diff --git a/Modules/FindMFC.cmake b/Modules/FindMFC.cmake
index 9738ac56f..e366619ce 100644
--- a/Modules/FindMFC.cmake
+++ b/Modules/FindMFC.cmake
@@ -5,7 +5,7 @@
FindMFC
-------
-Find MFC on Windows
+Find Microsoft Foundation Class Library (MFC) on Windows
Find the native MFC - i.e. decide if an application can link to the
MFC libraries.
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index 8c45a8c5f..a80f79987 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -216,7 +216,7 @@ If the following variables are set to true, the respective search will be perfor
and ``MPI_Fortran_<binding>_ASYNCPROT``, where ``<binding>`` is one of ``F77_HEADER``, ``F90_MODULE`` and
``F08_MODULE``.
``MPI_DETERMINE_LIBRARY_VERSION``
- For each language, find the output of ``MPI_Get_library_version`` and make it available as ``MPI_<lang>_LIBRARY_VERSION``.
+ For each language, find the output of ``MPI_Get_library_version`` and make it available as ``MPI_<lang>_LIBRARY_VERSION_STRING``.
This information is usually tied to the runtime component of an MPI implementation and might differ depending on ``<lang>``.
Note that the return value is entirely implementation defined. This information might be used to identify
the MPI vendor and for example pick the correct one of multiple third party binaries that matches the MPI vendor.
@@ -770,18 +770,20 @@ function (_MPI_interrogate_compiler LANG)
endforeach()
# Add the link directories given explicitly that we haven't used back as linker directories.
- foreach(_MPI_LINK_DIRECTORY IN LISTS MPI_LINK_DIRECTORIES_LEFTOVER)
- file(TO_NATIVE_PATH "${_MPI_LINK_DIRECTORY}" _MPI_LINK_DIRECTORY_ACTUAL)
- string(FIND "${_MPI_LINK_DIRECTORY_ACTUAL}" " " _MPI_LINK_DIRECTORY_CONTAINS_SPACE)
- if(NOT _MPI_LINK_DIRECTORY_CONTAINS_SPACE EQUAL -1)
- set(_MPI_LINK_DIRECTORY_ACTUAL "\"${_MPI_LINK_DIRECTORY_ACTUAL}\"")
- endif()
- if(MPI_LINK_FLAGS_WORK)
- string(APPEND MPI_LINK_FLAGS_WORK " ${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
- else()
- set(MPI_LINK_FLAGS_WORK "${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
- endif()
- endforeach()
+ if(NOT WIN32)
+ foreach(_MPI_LINK_DIRECTORY IN LISTS MPI_LINK_DIRECTORIES_LEFTOVER)
+ file(TO_NATIVE_PATH "${_MPI_LINK_DIRECTORY}" _MPI_LINK_DIRECTORY_ACTUAL)
+ string(FIND "${_MPI_LINK_DIRECTORY_ACTUAL}" " " _MPI_LINK_DIRECTORY_CONTAINS_SPACE)
+ if(NOT _MPI_LINK_DIRECTORY_CONTAINS_SPACE EQUAL -1)
+ set(_MPI_LINK_DIRECTORY_ACTUAL "\"${_MPI_LINK_DIRECTORY_ACTUAL}\"")
+ endif()
+ if(MPI_LINK_FLAGS_WORK)
+ string(APPEND MPI_LINK_FLAGS_WORK " ${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
+ else()
+ set(MPI_LINK_FLAGS_WORK "${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
+ endif()
+ endforeach()
+ endif()
# Deal with the libraries given with full path next
unset(MPI_DIRECT_LIB_NAMES_WORK)
@@ -1142,7 +1144,9 @@ macro(_MPI_create_imported_target LANG)
set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_LINK_LIBRARIES "")
if(MPI_${LANG}_LINK_FLAGS)
- set_property(TARGET MPI::MPI_${LANG} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${MPI_${LANG}_LINK_FLAGS}")
+ separate_arguments(_MPI_${LANG}_LINK_FLAGS NATIVE_COMMAND "${MPI_${LANG}_LINK_FLAGS}")
+ set_property(TARGET MPI::MPI_${LANG} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${_MPI_${LANG}_LINK_FLAGS}")
+ unset(_MPI_${LANG}_LINK_FLAGS)
endif()
# If the compiler links MPI implicitly, no libraries will be found as they're contained within
# CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES already.
@@ -1153,7 +1157,7 @@ macro(_MPI_create_imported_target LANG)
set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MPI_${LANG}_INCLUDE_DIRS}")
endmacro()
-function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY)
+function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY SUPPRESS_ERRORS)
set(WORK_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindMPI")
set(SRC_DIR "${CMAKE_ROOT}/Modules/FindMPI")
set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindMPI/${MPI_TEST_FILE_NAME}_${LANG}.bin")
@@ -1182,18 +1186,29 @@ function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY)
"${CMAKE_BINARY_DIR}" SOURCES "${MPI_TEST_SOURCE_FILE}"
COMPILE_DEFINITIONS ${MPI_TEST_COMPILE_DEFINITIONS}
LINK_LIBRARIES MPI::MPI_${LANG}
- RUN_OUTPUT_VARIABLE MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE})
+ RUN_OUTPUT_VARIABLE MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
+ COMPILE_OUTPUT_VARIABLE _MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT)
set(MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} "${MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}}" PARENT_SCOPE)
else()
try_compile(MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
"${CMAKE_BINARY_DIR}" SOURCES "${MPI_TEST_SOURCE_FILE}"
COMPILE_DEFINITIONS ${MPI_TEST_COMPILE_DEFINITIONS}
LINK_LIBRARIES MPI::MPI_${LANG}
- COPY_FILE "${BIN_FILE}")
+ COPY_FILE "${BIN_FILE}"
+ OUTPUT_VARIABLE _MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT)
+ endif()
+ if(NOT SUPPRESS_ERRORS)
+ if(NOT MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE} failed to compile with the following output:\n${_MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT}\n\n")
+ elseif(DEFINED MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} AND MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE} failed to run with the following output:\n${MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}}\n\n")
+ endif()
endif()
endfunction()
-macro(_MPI_check_lang_works LANG)
+macro(_MPI_check_lang_works LANG SUPPRESS_ERRORS)
# For Fortran we may have by the MPI-3 standard an implementation that provides:
# - the mpi_f08 module
# - *both*, the mpi module and 'mpif.h'
@@ -1201,9 +1216,9 @@ macro(_MPI_check_lang_works LANG)
if( NOT MPI_${LANG}_WORKS )
if("${LANG}" STREQUAL "Fortran")
set(MPI_Fortran_INTEGER_LINE "(kind=MPI_INTEGER_KIND)")
- _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER FALSE)
- _MPI_try_staged_settings(${LANG} test_mpi F90_MODULE FALSE)
- _MPI_try_staged_settings(${LANG} test_mpi F08_MODULE FALSE)
+ _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER FALSE ${SUPPRESS_ERRORS})
+ _MPI_try_staged_settings(${LANG} test_mpi F90_MODULE FALSE ${SUPPRESS_ERRORS})
+ _MPI_try_staged_settings(${LANG} test_mpi F08_MODULE FALSE ${SUPPRESS_ERRORS})
set(MPI_${LANG}_WORKS FALSE)
@@ -1219,14 +1234,14 @@ macro(_MPI_check_lang_works LANG)
# However, MPI-1 also did not define the Fortran 90 and 08 modules, so we only try the F77 header.
unset(MPI_Fortran_INTEGER_LINE)
if(NOT MPI_${LANG}_WORKS)
- _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER_NOKIND FALSE)
+ _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER_NOKIND FALSE ${SUPPRESS_ERRORS})
if(MPI_RESULT_${LANG}_test_mpi_F77_HEADER_NOKIND)
set(MPI_${LANG}_WORKS TRUE)
set(MPI_${LANG}_HAVE_F77_HEADER TRUE)
endif()
endif()
else()
- _MPI_try_staged_settings(${LANG} test_mpi normal FALSE)
+ _MPI_try_staged_settings(${LANG} test_mpi normal FALSE ${SUPPRESS_ERRORS})
# If 'test_mpi' built correctly, we've found valid MPI settings. There might not be MPI-2 C++ support, but there can't
# be MPI-2 C++ support without the C bindings being present, so checking for them is sufficient.
set(MPI_${LANG}_WORKS "${MPI_RESULT_${LANG}_test_mpi_normal}")
@@ -1388,7 +1403,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
# Should the imported targets be empty, we effectively try whether the compiler supports MPI on its own, which is the case on e.g.
# Cray PrgEnv.
_MPI_create_imported_target(${LANG})
- _MPI_check_lang_works(${LANG})
+ _MPI_check_lang_works(${LANG} TRUE)
# If the compiler can build MPI code on its own, it functions as an MPI compiler and we'll set the variable to point to it.
if(MPI_${LANG}_WORKS)
@@ -1440,7 +1455,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
# If we haven't made the implicit compiler test yet, perform it now.
if(NOT MPI_${LANG}_TRIED_IMPLICIT)
_MPI_create_imported_target(${LANG})
- _MPI_check_lang_works(${LANG})
+ _MPI_check_lang_works(${LANG} TRUE)
endif()
# Should the MPI compiler not work implicitly for MPI, still interrogate it.
@@ -1486,7 +1501,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
_MPI_create_imported_target(${LANG})
if(NOT MPI_${LANG}_WORKS)
- _MPI_check_lang_works(${LANG})
+ _MPI_check_lang_works(${LANG} FALSE)
endif()
# Next, we'll initialize the MPI variables that have not been previously set.
@@ -1505,7 +1520,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
if(MPI_${LANG}_WORKS)
if("${LANG}" STREQUAL "CXX" AND NOT DEFINED MPI_MPICXX_FOUND)
if(NOT MPI_CXX_SKIP_MPICXX AND NOT MPI_CXX_VALIDATE_SKIP_MPICXX)
- _MPI_try_staged_settings(${LANG} test_mpi MPICXX FALSE)
+ _MPI_try_staged_settings(${LANG} test_mpi MPICXX FALSE FALSE)
if(MPI_RESULT_${LANG}_test_mpi_MPICXX)
set(MPI_MPICXX_FOUND TRUE)
else()
@@ -1540,7 +1555,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
# and MPI_SUBVERSION are provided. These defines did not exist in MPI 1.0 and 1.1 and therefore might not
# exist. For C/C++, test_mpi.c will handle the MPI_VERSION extraction, but for Fortran, we need mpiver.f90.
if(NOT DEFINED MPI_${LANG}_VERSION)
- _MPI_try_staged_settings(${LANG} mpiver ${MPI_${LANG}_HIGHEST_METHOD} FALSE)
+ _MPI_try_staged_settings(${LANG} mpiver ${MPI_${LANG}_HIGHEST_METHOD} FALSE FALSE)
if(MPI_RESULT_${LANG}_mpiver_${MPI_${LANG}_HIGHEST_METHOD})
file(STRINGS ${MPI_BIN_FOLDER}/mpiver_${LANG}.bin _MPI_VERSION_STRING LIMIT_COUNT 1 REGEX "INFO:MPI-VER")
if("${_MPI_VERSION_STRING}" MATCHES ".*INFO:MPI-VER\\[([0-9]+)\\.([0-9]+)\\].*")
@@ -1559,7 +1574,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
if(MPI_${LANG}_HAVE_${mpimethod})
set(MPI_${LANG}_${mpimethod}_SUBARRAYS FALSE)
set(MPI_${LANG}_${mpimethod}_ASYNCPROT FALSE)
- _MPI_try_staged_settings(${LANG} fortranparam_mpi ${mpimethod} TRUE)
+ _MPI_try_staged_settings(${LANG} fortranparam_mpi ${mpimethod} TRUE FALSE)
if(MPI_RESULT_${LANG}_fortranparam_mpi_${mpimethod} AND
NOT "${MPI_RUN_RESULT_${LANG}_fortranparam_mpi_${mpimethod}}" STREQUAL "FAILED_TO_RUN")
if("${MPI_RUN_OUTPUT_${LANG}_fortranparam_mpi_${mpimethod}}" MATCHES
@@ -1600,7 +1615,7 @@ foreach(LANG IN ITEMS C CXX Fortran)
# It's also worth noting that the installed version string can depend on the language, or on the system the binary
# runs on if MPI is not statically linked.
if(MPI_DETERMINE_LIBRARY_VERSION AND NOT MPI_${LANG}_LIBRARY_VERSION_STRING)
- _MPI_try_staged_settings(${LANG} libver_mpi ${MPI_${LANG}_HIGHEST_METHOD} TRUE)
+ _MPI_try_staged_settings(${LANG} libver_mpi ${MPI_${LANG}_HIGHEST_METHOD} TRUE FALSE)
if(MPI_RESULT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD} AND
"${MPI_RUN_RESULT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD}}" EQUAL "0")
string(STRIP "${MPI_RUN_OUTPUT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD}}"
diff --git a/Modules/FindMPI/libver_mpi.c b/Modules/FindMPI/libver_mpi.c
index 18d4a60ef..d89328a01 100644
--- a/Modules/FindMPI/libver_mpi.c
+++ b/Modules/FindMPI/libver_mpi.c
@@ -16,4 +16,5 @@ int main(int argc, char* argv[])
#else
puts(mpilibver_str);
#endif
+ return 0;
}
diff --git a/Modules/FindMPI/test_mpi.c b/Modules/FindMPI/test_mpi.c
index 05cec89b5..7c96d54a8 100644
--- a/Modules/FindMPI/test_mpi.c
+++ b/Modules/FindMPI/test_mpi.c
@@ -34,4 +34,5 @@ int main(int argc, char* argv[])
MPI_Init(&argc, &argv);
MPI_Finalize();
#endif
+ return 0;
}
diff --git a/Modules/FindOpenAL.cmake b/Modules/FindOpenAL.cmake
index dbd796101..27dcaf5e9 100644
--- a/Modules/FindOpenAL.cmake
+++ b/Modules/FindOpenAL.cmake
@@ -6,15 +6,15 @@ FindOpenAL
----------
+Finds Open Audio Library (OpenAL).
+This module defines ``OPENAL_LIBRARY OPENAL_FOUND``, if
+false, do not try to link to OpenAL ``OPENAL_INCLUDE_DIR``, where to find
+the headers.
-Locate OpenAL This module defines OPENAL_LIBRARY OPENAL_FOUND, if
-false, do not try to link to OpenAL OPENAL_INCLUDE_DIR, where to find
-the headers
+``$OPENALDIR`` is an environment variable that would correspond to the
+``./configure --prefix=$OPENALDIR`` used in building OpenAL.
-$OPENALDIR is an environment variable that would correspond to the
-./configure --prefix=$OPENALDIR used in building OpenAL.
-
-Created by Eric Wing. This was influenced by the FindSDL.cmake
+Created by Eric Wing. This was influenced by the ``FindSDL.cmake``
module.
#]=======================================================================]
@@ -63,9 +63,6 @@ find_path(OPENAL_INCLUDE_DIR al.h
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw # Fink
- /opt/local # DarwinPorts
- /opt/csw # Blastwave
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
)
@@ -84,9 +81,6 @@ find_library(OPENAL_LIBRARY
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw
- /opt/local
- /opt/csw
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
)
diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake
index 79c0382d3..9891724e4 100644
--- a/Modules/FindOpenCL.cmake
+++ b/Modules/FindOpenCL.cmake
@@ -5,7 +5,7 @@
FindOpenCL
----------
-Try to find OpenCL
+Finds Open Computing Language (OpenCL)
IMPORTED Targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
index 00db033d3..23bb001de 100644
--- a/Modules/FindOpenGL.cmake
+++ b/Modules/FindOpenGL.cmake
@@ -5,7 +5,7 @@
FindOpenGL
----------
-FindModule for OpenGL and GLU.
+FindModule for OpenGL and OpenGL Utility Library (GLU).
Optional COMPONENTS
^^^^^^^^^^^^^^^^^^^
@@ -23,9 +23,9 @@ This module defines the :prop_tgt:`IMPORTED` targets:
``OpenGL::OpenGL``
Defined to libOpenGL if the system is GLVND-based.
``OpenGL::GLU``
- Defined if the system has GLU.
+ Defined if the system has OpenGL Utility Library (GLU).
``OpenGL::GLX``
- Defined if the system has GLX.
+ Defined if the system has OpenGL Extension to the X Window System (GLX).
``OpenGL::EGL``
Defined if the system has EGL.
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 7e3721276..def23bb13 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -5,7 +5,7 @@
FindOpenMP
----------
-Finds OpenMP support
+Finds Open Multi-Processing (OpenMP) support.
This module can be used to detect OpenMP support in a compiler. If
the compiler supports OpenMP, the flags required to compile with
@@ -96,7 +96,6 @@ function(_OPENMP_FLAG_CANDIDATES LANG)
else()
set(OMP_FLAG_Intel "-qopenmp")
endif()
- set(OMP_FLAG_MIPSpro "-mp")
set(OMP_FLAG_MSVC "-openmp")
set(OMP_FLAG_PathScale "-openmp")
set(OMP_FLAG_NAG "-openmp")
@@ -348,6 +347,7 @@ macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
# Preview versions
"201611=5.0" # OpenMP 5.0 preview 1
# Combined versions, 2.5 onwards
+ "201811=5.0"
"201511=4.5"
"201307=4.0"
"201107=3.1"
@@ -364,6 +364,9 @@ macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
# Fortran version 1.0
"199710=1.0"
)
+ if(MSVC)
+ list(APPEND OpenMP_SPEC_DATE_MAP "2019=2.0")
+ endif()
if(OpenMP_${LANG}_SPEC_DATE)
string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
diff --git a/Modules/FindOpenSceneGraph.cmake b/Modules/FindOpenSceneGraph.cmake
index 6f7d3c836..27909bcea 100644
--- a/Modules/FindOpenSceneGraph.cmake
+++ b/Modules/FindOpenSceneGraph.cmake
@@ -5,11 +5,11 @@
FindOpenSceneGraph
------------------
-Find OpenSceneGraph
+Find OpenSceneGraph (3D graphics application programming interface)
This module searches for the OpenSceneGraph core "osg" library as well
-as OpenThreads, and whatever additional COMPONENTS (nodekits) that you
-specify.
+as :module:`FindOpenThreads`, and whatever additional ``COMPONENTS``
+(nodekits) that you specify.
::
@@ -17,10 +17,11 @@ specify.
-NOTE: To use this module effectively you must either require CMake >=
-2.6.3 with cmake_minimum_required(VERSION 2.6.3) or download and place
-FindOpenThreads.cmake, Findosg_functions.cmake, Findosg.cmake, and
-Find<etc>.cmake files into your CMAKE_MODULE_PATH.
+NOTE: To use this module effectively you must either require ``CMake >=
+2.6.3`` with :command:`cmake_minimum_required(VERSION 2.6.3)` or download
+and place :module:`FindOpenThreads`, :module:`Findosg` functions,
+:module:`Findosg` and ``Find<etc>.cmake`` files into your
+:variable:`CMAKE_MODULE_PATH`.
==================================
@@ -40,11 +41,12 @@ This module accepts the following variables (note mixed case)
The following environment variables are also respected for finding the
-OSG and it's various components. CMAKE_PREFIX_PATH can also be used
-for this (see find_library() CMake documentation).
+OSG and it's various components. :variable:`CMAKE_PREFIX_PATH` can also be
+used for this (see :command:`find_library` CMake documentation).
``<MODULE>_DIR``
- (where MODULE is of the form "OSGVOLUME" and there is a FindosgVolume.cmake file)
+ (where ``MODULE`` is of the form "OSGVOLUME" and there is
+ a :module:`FindosgVolume`.cmake` file)
``OSG_DIR``
..
``OSGDIR``
@@ -53,7 +55,7 @@ for this (see find_library() CMake documentation).
..
-[CMake 2.8.10]: The CMake variable OSG_DIR can now be used as well to
+[CMake 2.8.10]: The CMake variable ``OSG_DIR`` can now be used as well to
influence detection, instead of needing to specify an environment
variable.
diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake
index 2208b4847..a7908c5c3 100644
--- a/Modules/FindPNG.cmake
+++ b/Modules/FindPNG.cmake
@@ -100,13 +100,14 @@ if(ZLIB_FOUND)
# No need to define PNG_USE_DLL here, because it's default for Cygwin.
else()
set (PNG_DEFINITIONS -DPNG_STATIC)
+ set(_PNG_COMPILE_DEFINITIONS PNG_STATIC)
endif()
endif ()
if(NOT TARGET PNG::PNG)
add_library(PNG::PNG UNKNOWN IMPORTED)
set_target_properties(PNG::PNG PROPERTIES
- INTERFACE_COMPILE_DEFINITIONS "${PNG_DEFINITIONS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_PNG_COMPILE_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${PNG_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
if(EXISTS "${PNG_LIBRARY}")
@@ -129,6 +130,8 @@ if(ZLIB_FOUND)
IMPORTED_LOCATION_DEBUG "${PNG_LIBRARY_DEBUG}")
endif()
endif()
+
+ unset(_PNG_COMPILE_DEFINITIONS)
endif ()
if (PNG_PNG_INCLUDE_DIR AND EXISTS "${PNG_PNG_INCLUDE_DIR}/png.h")
diff --git a/Modules/FindPhysFS.cmake b/Modules/FindPhysFS.cmake
index 0366f77a3..a32f83aae 100644
--- a/Modules/FindPhysFS.cmake
+++ b/Modules/FindPhysFS.cmake
@@ -24,9 +24,6 @@ find_path(PHYSFS_INCLUDE_DIR physfs.h
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw # Fink
- /opt/local # DarwinPorts
- /opt/csw # Blastwave
/opt
)
@@ -38,9 +35,6 @@ find_library(PHYSFS_LIBRARY
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw
- /opt/local
- /opt/csw
/opt
)
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index e19242626..e05d5c8e5 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -84,26 +84,8 @@ macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp)
endif()
endmacro()
-#[========================================[.rst:
-.. command:: pkg_get_variable
-
- Retrieves the value of a pkg-config variable ``varName`` and stores it in the
- result variable ``resultVar`` in the calling scope.
-
- .. code-block:: cmake
-
- pkg_get_variable(<resultVar> <moduleName> <varName>)
-
- If ``pkg-config`` returns multiple values for the specified variable,
- ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
-
- For example:
-
- .. code-block:: cmake
-
- pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
-#]========================================]
-function (pkg_get_variable result pkg variable)
+# Internal version of pkg_get_variable; expects PKG_CONFIG_PATH to already be set
+function (_pkg_get_variable result pkg variable)
_pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
set("${result}"
"${prefix_result}"
@@ -242,7 +224,7 @@ endfunction()
function(_pkg_create_imp_target _prefix _imp_target_global)
# only create the target if it is linkable, i.e. no executables
if (NOT TARGET PkgConfig::${_prefix}
- AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_CFLAGS_OTHER ))
+ AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_LDFLAGS_OTHER OR ${_prefix}_CFLAGS_OTHER ))
if(${_imp_target_global})
set(_global_opt "GLOBAL")
else()
@@ -258,6 +240,10 @@ function(_pkg_create_imp_target _prefix _imp_target_global)
set_property(TARGET PkgConfig::${_prefix} PROPERTY
INTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}")
endif()
+ if(${_prefix}_LDFLAGS_OTHER)
+ set_property(TARGET PkgConfig::${_prefix} PROPERTY
+ INTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}")
+ endif()
if(${_prefix}_CFLAGS_OTHER)
set_property(TARGET PkgConfig::${_prefix} PROPERTY
INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}")
@@ -275,6 +261,102 @@ macro(_pkg_recalculate _prefix _no_cmake_path _no_cmake_environment_path _imp_ta
endmacro()
###
+macro(_pkg_set_path_internal)
+ set(_extra_paths)
+
+ if(NOT _no_cmake_path)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH)
+ endif()
+
+ if(NOT _no_cmake_environment_path)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH)
+ endif()
+
+ if(NOT _extra_paths STREQUAL "")
+ # Save the PKG_CONFIG_PATH environment variable, and add paths
+ # from the CMAKE_PREFIX_PATH variables
+ set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}")
+ set(_pkgconfig_path "${_pkgconfig_path_old}")
+ if(NOT _pkgconfig_path STREQUAL "")
+ file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+ endif()
+
+ # Create a list of the possible pkgconfig subfolder (depending on
+ # the system
+ set(_lib_dirs)
+ if(NOT DEFINED CMAKE_SYSTEM_NAME
+ OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+ AND NOT CMAKE_CROSSCOMPILING))
+ if(EXISTS "/etc/debian_version") # is this a debian system ?
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
+ endif()
+ else()
+ # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties
+ get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
+ if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
+ list(APPEND _lib_dirs "lib32/pkgconfig")
+ endif()
+ get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+ if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND _lib_dirs "lib64/pkgconfig")
+ endif()
+ get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS)
+ if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32")
+ list(APPEND _lib_dirs "libx32/pkgconfig")
+ endif()
+ endif()
+ endif()
+ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING)
+ list(APPEND _lib_dirs "libdata/pkgconfig")
+ endif()
+ list(APPEND _lib_dirs "lib/pkgconfig")
+ list(APPEND _lib_dirs "share/pkgconfig")
+
+ # Check if directories exist and eventually append them to the
+ # pkgconfig path list
+ foreach(_prefix_dir ${_extra_paths})
+ foreach(_lib_dir ${_lib_dirs})
+ if(EXISTS "${_prefix_dir}/${_lib_dir}")
+ list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
+ list(REMOVE_DUPLICATES _pkgconfig_path)
+ endif()
+ endforeach()
+ endforeach()
+
+ # Prepare and set the environment variable
+ if(NOT _pkgconfig_path STREQUAL "")
+ # remove empty values from the list
+ list(REMOVE_ITEM _pkgconfig_path "")
+ file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+ if(UNIX)
+ string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
+ string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
+ endif()
+ set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}")
+ endif()
+
+ # Unset variables
+ unset(_lib_dirs)
+ unset(_pkgconfig_path)
+ endif()
+endmacro()
+
+macro(_pkg_restore_path_internal)
+ if(NOT _extra_paths STREQUAL "")
+ # Restore the environment variable
+ set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
+ endif()
+
+ unset(_extra_paths)
+ unset(_pkgconfig_path_old)
+endmacro()
+
+###
macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global _prefix)
_pkgconfig_unset(${_prefix}_FOUND)
_pkgconfig_unset(${_prefix}_VERSION)
@@ -314,88 +396,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
set(_pkg_check_modules_packages)
set(_pkg_check_modules_failed)
- set(_extra_paths)
-
- if(NOT _no_cmake_path)
- _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH)
- _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH)
- _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH)
- endif()
-
- if(NOT _no_cmake_environment_path)
- _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH)
- _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH)
- _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH)
- endif()
-
- if(NOT "${_extra_paths}" STREQUAL "")
- # Save the PKG_CONFIG_PATH environment variable, and add paths
- # from the CMAKE_PREFIX_PATH variables
- set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}")
- set(_pkgconfig_path "${_pkgconfig_path_old}")
- if(NOT "${_pkgconfig_path}" STREQUAL "")
- file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
- endif()
-
- # Create a list of the possible pkgconfig subfolder (depending on
- # the system
- set(_lib_dirs)
- if(NOT DEFINED CMAKE_SYSTEM_NAME
- OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
- AND NOT CMAKE_CROSSCOMPILING))
- if(EXISTS "/etc/debian_version") # is this a debian system ?
- if(CMAKE_LIBRARY_ARCHITECTURE)
- list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
- endif()
- else()
- # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties
- get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
- if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
- list(APPEND _lib_dirs "lib32/pkgconfig")
- endif()
- get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
- if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- list(APPEND _lib_dirs "lib64/pkgconfig")
- endif()
- get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS)
- if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32")
- list(APPEND _lib_dirs "libx32/pkgconfig")
- endif()
- endif()
- endif()
- if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING)
- list(APPEND _lib_dirs "libdata/pkgconfig")
- endif()
- list(APPEND _lib_dirs "lib/pkgconfig")
- list(APPEND _lib_dirs "share/pkgconfig")
-
- # Check if directories exist and eventually append them to the
- # pkgconfig path list
- foreach(_prefix_dir ${_extra_paths})
- foreach(_lib_dir ${_lib_dirs})
- if(EXISTS "${_prefix_dir}/${_lib_dir}")
- list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
- list(REMOVE_DUPLICATES _pkgconfig_path)
- endif()
- endforeach()
- endforeach()
-
- # Prepare and set the environment variable
- if(NOT "${_pkgconfig_path}" STREQUAL "")
- # remove empty values from the list
- list(REMOVE_ITEM _pkgconfig_path "")
- file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
- if(UNIX)
- string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
- string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
- endif()
- set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}")
- endif()
-
- # Unset variables
- unset(_lib_dirs)
- unset(_pkgconfig_path)
- endif()
+ _pkg_set_path_internal()
# iterate through module list and check whether they exist and match the required version
foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list})
@@ -498,13 +499,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
_pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global})
endif()
- if(NOT "${_extra_paths}" STREQUAL "")
- # Restore the environment variable
- set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
- endif()
-
- unset(_extra_paths)
- unset(_pkgconfig_path_old)
+ _pkg_restore_path_internal()
else()
if (${_is_required})
message(SEND_ERROR "pkg-config tool not found")
@@ -708,6 +703,34 @@ macro(pkg_search_module _prefix _module0)
endif()
endmacro()
+#[========================================[.rst:
+.. command:: pkg_get_variable
+
+ Retrieves the value of a pkg-config variable ``varName`` and stores it in the
+ result variable ``resultVar`` in the calling scope.
+
+ .. code-block:: cmake
+
+ pkg_get_variable(<resultVar> <moduleName> <varName>)
+
+ If ``pkg-config`` returns multiple values for the specified variable,
+ ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
+
+ For example:
+
+ .. code-block:: cmake
+
+ pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
+#]========================================]
+function (pkg_get_variable result pkg variable)
+ _pkg_set_path_internal()
+ _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
+ set("${result}"
+ "${prefix_result}"
+ PARENT_SCOPE)
+ _pkg_restore_path_internal()
+endfunction ()
+
#[========================================[.rst:
Variables Affecting Behavior
diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake
index 4b5e60e21..dfece229e 100644
--- a/Modules/FindPostgreSQL.cmake
+++ b/Modules/FindPostgreSQL.cmake
@@ -155,17 +155,38 @@ if ( WIN32 )
set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
endif()
-find_library(PostgreSQL_LIBRARY
- NAMES ${PostgreSQL_LIBRARY_TO_FIND}
- PATHS
- ${PostgreSQL_ROOT_DIRECTORIES}
- PATH_SUFFIXES
- lib
- ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
- # Help the user find it if we cannot.
- DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}"
-)
-get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH)
+function(__postgresql_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ PATHS
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ lib
+ ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}"
+ )
+endfunction()
+
+# For compatibility with versions prior to this multi-config search, honor
+# any PostgreSQL_LIBRARY that is already specified and skip the search.
+if(PostgreSQL_LIBRARY)
+ set(PostgreSQL_LIBRARIES "${PostgreSQL_LIBRARY}")
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY}" PATH)
+else()
+ __postgresql_find_library(PostgreSQL_LIBRARY_RELEASE ${PostgreSQL_LIBRARY_TO_FIND})
+ __postgresql_find_library(PostgreSQL_LIBRARY_DEBUG ${PostgreSQL_LIBRARY_TO_FIND}d)
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(PostgreSQL)
+ mark_as_advanced(PostgreSQL_LIBRARY_RELEASE PostgreSQL_LIBRARY_DEBUG)
+ if(PostgreSQL_LIBRARY_RELEASE)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_RELEASE}" PATH)
+ elseif(PostgreSQL_LIBRARY_DEBUG)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_DEBUG}" PATH)
+ else()
+ set(PostgreSQL_LIBRARY_DIR "")
+ endif()
+endif()
if (PostgreSQL_INCLUDE_DIR)
# Some platforms include multiple pg_config.hs for multi-lib configurations
@@ -213,17 +234,36 @@ find_package_handle_standard_args(PostgreSQL
VERSION_VAR PostgreSQL_VERSION_STRING)
set(PostgreSQL_FOUND ${POSTGRESQL_FOUND})
+function(__postgresql_import_library _target _var _config)
+ if(_config)
+ set(_config_suffix "_${_config}")
+ else()
+ set(_config_suffix "")
+ endif()
+
+ set(_lib "${${_var}${_config_suffix}}")
+ if(EXISTS "${_lib}")
+ if(_config)
+ set_property(TARGET ${_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS ${_config})
+ endif()
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_LOCATION${_config_suffix} "${_lib}")
+ endif()
+endfunction()
+
# Now try to get the include and library path.
if(PostgreSQL_FOUND)
if (NOT TARGET PostgreSQL::PostgreSQL)
add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
- IMPORTED_LOCATION "${PostgreSQL_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIR};${PostgreSQL_TYPE_INCLUDE_DIR}")
+ __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} )
- set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY})
endif()
-mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR PostgreSQL_LIBRARY )
+mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR)
diff --git a/Modules/FindProducer.cmake b/Modules/FindProducer.cmake
index fba0494e3..65495b5ba 100644
--- a/Modules/FindProducer.cmake
+++ b/Modules/FindProducer.cmake
@@ -45,12 +45,9 @@ find_path(PRODUCER_INCLUDE_DIR Producer/CameraGroup
PATHS
~/Library/Frameworks
/Library/Frameworks
- /sw/include # Fink
- /opt/local/include # DarwinPorts
- /opt/csw/include # Blastwave
- /opt/include
- [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]/include
- [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
+ /opt
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]
)
find_library(PRODUCER_LIBRARY
@@ -61,9 +58,6 @@ find_library(PRODUCER_LIBRARY
ENV OSGDIR
PATH_SUFFIXES lib
PATHS
- /sw
- /opt/local
- /opt/csw
/opt
)
diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake
index 1758fb355..76bc873fd 100644
--- a/Modules/FindProtobuf.cmake
+++ b/Modules/FindProtobuf.cmake
@@ -207,9 +207,14 @@ function(protobuf_generate)
get_filename_component(_basename ${_proto} NAME_WE)
file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
+ set(_possible_rel_dir)
+ if (NOT protobuf_generate_APPEND_PATH)
+ set(_possible_rel_dir ${_rel_dir}/)
+ endif()
+
set(_generated_srcs)
foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS})
- list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_basename}${_ext}")
+ list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}")
endforeach()
if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp)
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 1c134e278..e2f3bf349 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -46,7 +46,11 @@ This module defines the following :ref:`Imported Targets <Imported Targets>`
``Python::Compiler``
Python compiler. Target defined if component ``Compiler`` is found.
``Python::Python``
- Python library. Target defined if component ``Development`` is found.
+ Python library for Python embedding. Target defined if component
+ ``Development`` is found.
+``Python::Module``
+ Python library for Python module. Target defined if component ``Development``
+ is found.
``Python::NumPy``
NumPy Python library. Target defined if component ``NumPy`` is found.
@@ -133,6 +137,19 @@ Hints
* If set to TRUE, search **only** for static libraries.
* If set to FALSE, search **only** for shared libraries.
+``Python_FIND_STRATEGY``
+ This variable defines how lookup will be done.
+ The ``Python_FIND_STRATEGY`` variable can be set to empty or one of the
+ following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
``Python_FIND_REGISTRY``
On Windows the ``Python_FIND_REGISTRY`` variable determine the order
of preference between registry and environment variables.
@@ -144,28 +161,45 @@ Hints
* ``LAST``: Try to use registry after environment variables.
* ``NEVER``: Never try to use registry.
-``CMAKE_FIND_FRAMEWORK``
- On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+``Python_FIND_FRAMEWORK``
+ On macOS the ``Python_FIND_FRAMEWORK`` variable determine the order of
preference between Apple-style and unix-style package components.
+ This variable can be set to empty or take same values as
+ :variable:`CMAKE_FIND_FRAMEWORK` variable.
.. note::
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+ If ``Python_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ only when a virtual environment is active (i.e. the ``activate`` script has
+ been evaluated). In this case, it takes precedence over
+ ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+ The ``Python_FIND_VIRTUALENV`` variable can be set to empty or one of the
+ following:
- If a Python virtual environment is configured, set variable
- ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
- value ``LAST`` or ``NEVER`` to select it preferably.
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter. In this case, variable ``Python_FIND_REGISTRY`` (Windows)
+ or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
Commands
^^^^^^^^
This module defines the command ``Python_add_library`` (when
:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
-:command:`add_library`, but takes care of Python module naming rules
-(only applied if library is of type ``MODULE``), and adds a dependency to target
-``Python::Python``::
+:command:`add_library` and adds a dependency to target ``Python::Python`` or,
+when library type is ``MODULE``, to target ``Python::Module`` and takes care of
+Python module naming rules::
Python_add_library (my_module MODULE src1.cpp)
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 544e62bc8..49d8e26cd 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -5,8 +5,14 @@
# This file is a "template" file used by various FindPython modules.
#
+cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY)
+
cmake_policy (VERSION 3.7)
+if (_${_PYTHON_PREFIX}_LOOKUP_POLICY)
+ cmake_policy (SET CMP0094 ${_${_PYTHON_PREFIX}_LOOKUP_POLICY})
+endif()
+
#
# Initial configuration
#
@@ -74,14 +80,78 @@ function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS _PYTHON_VERSION)
set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${_PYTHON_FRAMEWORK_PATHS} PARENT_SCOPE)
endfunction()
+function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS _PYTHON_VERSION)
+ string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PYTHON_VERSION})
+ set (${_PYTHON_PGR_REGISTRY_PATHS}
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES _PYTHON_VERSION _PYTHON_TYPE)
+ set (path_suffixes)
+
+ if (_PYTHON_TYPE STREQUAL "LIBRARY")
+ if (CMAKE_LIBRARY_ARCHITECTURE)
+ list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE})
+ endif()
+ list (APPEND path_suffixes lib libs)
+
+ if (CMAKE_LIBRARY_ARCHITECTURE)
+ list (APPEND path_suffixes lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}mu-${CMAKE_LIBRARY_ARCHITECTURE}
+ lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}m-${CMAKE_LIBRARY_ARCHITECTURE}
+ lib/python${_PYTHON_VERSION}/config-${CMAKE_MATCH_1}u-${CMAKE_LIBRARY_ARCHITECTURE}
+ lib/python${_PYTHON_VERSION}/config-${CMAKE_MATCH_1}-${CMAKE_LIBRARY_ARCHITECTURE})
+ endif()
+ list (APPEND path_suffixes lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}mu
+ lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}m
+ lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}u
+ lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}
+ lib/python${_PYTHON_VERSION}/config)
+
+ elseif (_PYTHON_TYPE STREQUAL "INCLUDE")
+ list (APPEND path_suffixes include/python${_PYTHON_VERSION}mu
+ include/python${_PYTHON_VERSION}m
+ include/python${_PYTHON_VERSION}u
+ include/python${_PYTHON_VERSION}
+ include)
+ endif()
+
+ set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_LIB_NAMES _PYTHON_PGLN_NAMES _PYTHON_VERSION)
+ string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PYTHON_VERSION})
+
+ if (ARGC EQUAL 3 AND ARGV2 STREQUAL "DEBUG")
+ set (${_PYTHON_PGLN_NAMES} python${_PYTHON_VERSION_NO_DOTS}_d PARENT_SCOPE)
+ else()
+ set (${_PYTHON_PGLN_NAMES} python${_PYTHON_VERSION_NO_DOTS}
+ python${_PYTHON_VERSION}mu
+ python${_PYTHON_VERSION}m
+ python${_PYTHON_VERSION}u
+ python${_PYTHON_VERSION}
+ PARENT_SCOPE)
+ endif()
+endfunction()
+
function (_PYTHON_VALIDATE_INTERPRETER)
if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
return()
endif()
- if (ARGC EQUAL 1)
- set (expected_version ${ARGV0})
+ cmake_parse_arguments (_PVI "EXACT" "" "" ${ARGN})
+ if (_PVI_UNPARSED_ARGUMENTS)
+ set (expected_version ${_PVI_UNPARSED_ARGUMENTS})
else()
unset (expected_version)
endif()
@@ -96,7 +166,7 @@ function (_PYTHON_VALIDATE_INTERPRETER)
OUTPUT_VARIABLE version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
- if (result OR NOT version EQUAL expected_version)
+ if (result OR (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
# interpreter not usable or has wrong major version
set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
return()
@@ -142,9 +212,24 @@ function (_PYTHON_VALIDATE_COMPILER expected_version)
return()
endif()
+ cmake_parse_arguments (_PVC "EXACT" "" "" ${ARGN})
+ if (_PVC_UNPARSED_ARGUMENTS)
+ set (major_version FALSE)
+ set (expected_version ${_PVC_UNPARSED_ARGUMENTS})
+ else()
+ set (major_version TRUE)
+ set (expected_version ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR})
+ set (_PVC_EXACT TRUE)
+ endif()
+
# retrieve python environment version from compiler
set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
- file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n")
+ if (major_version)
+ # check only major version
+ file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write(str(sys.version_info[0]))")
+ else()
+ file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n")
+ endif()
execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${working_dir}/version.py"
WORKING_DIRECTORY "${working_dir}"
OUTPUT_QUIET
@@ -157,8 +242,8 @@ function (_PYTHON_VALIDATE_COMPILER expected_version)
ERROR_QUIET)
file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
- if (result OR NOT version EQUAL expected_version)
- # Compiler not usable or has wrong major version
+ if (result OR (_PVC_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
+ # Compiler not usable or has wrong version
set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE)
endif()
endfunction()
@@ -236,6 +321,21 @@ if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
endif()
endif()
+# Define lookup strategy
+if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW")
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION")
+else()
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
+endif()
+if (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY)
+ if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES "^(VERSION|LOCATION)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.")
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "${${_PYTHON_PREFIX}_FIND_STRATEGY}")
+ endif()
+endif()
+
# Python and Anaconda distributions: define which architectures can be used
if (CMAKE_SIZEOF_VOID_P)
# In this case, search only for 64bit or 32bit
@@ -261,6 +361,24 @@ set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40)
# Apple frameworks handling
_python_find_frameworks ()
+set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
+
+if (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK)
+ if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK})
+ endif()
+elseif (DEFINED CMAKE_FIND_FRAMEWORK)
+ if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.")
+ elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+ endif()
+endif()
+
# Save CMAKE_FIND_APPBUNDLE
if (DEFINED CMAKE_FIND_APPBUNDLE)
set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE})
@@ -273,15 +391,8 @@ set (CMAKE_FIND_APPBUNDLE "NEVER")
# Save CMAKE_FIND_FRAMEWORK
if (DEFINED CMAKE_FIND_FRAMEWORK)
set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
- if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
- message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.")
- set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
- else()
- set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
- endif()
else()
unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)
- set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
endif()
# To avoid framework lookup
set (CMAKE_FIND_FRAMEWORK "NEVER")
@@ -289,7 +400,7 @@ set (CMAKE_FIND_FRAMEWORK "NEVER")
# Windows Registry handling
if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY)
if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$")
- message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected.")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
else()
set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY})
@@ -298,6 +409,22 @@ else()
set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
endif()
+# virtual environments handling
+if (DEFINED ENV{VIRTUAL_ENV})
+ if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)
+ if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV})
+ endif()
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST)
+ endif()
+else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)
+endif()
+
unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
unset (_${_PYTHON_PREFIX}_CACHED_VARS)
@@ -312,141 +439,265 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
- # look-up for various versions and locations
- foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
- string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ unset (_${_PYTHON_PREFIX}_NAMES)
+ unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ unset (_${_PYTHON_PREFIX}_REGISTRY_PATHS)
- _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # build all executable names
+ list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_VERSION})
+
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ list (APPEND _${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS})
+
+ # Registry Paths
+ _python_get_registries (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath])
+ endforeach()
+ list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+
+ while (TRUE)
+ # Virtual environments handling
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ENV VIRTUAL_ENV
+ PATH_SUFFIXES bin Scripts
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ if (NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ break()
+ endif()
+ endif()
+
+ # Apple frameworks handling
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
- # Apple frameworks handling
- if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ # try using HINTS and standard paths
find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
NAMES_PER_DIR
- PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
- PATH_SUFFIXES bin
- NO_CMAKE_PATH
- NO_CMAKE_ENVIRONMENT_PATH
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
- endif()
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
- # Windows registry
- if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ # Apple frameworks handling
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_DEFAULT_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+
+ break()
+ endwhile()
+ else()
+ # look-up for various versions and locations
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ set (_${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_VERSION}
+ python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+ python)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+
+ # Virtual environments handling
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ENV VIRTUAL_ENV
+ PATH_SUFFIXES bin Scripts
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ continue()
+ endif()
+ endif()
+
+ # Apple frameworks handling
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # Windows registry
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
+ PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+
+ # try using HINTS
find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- python
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
- PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- endif()
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ # try using standard paths.
+ # NAMES_PER_DIR is not defined on purpose to have a chance to find
+ # expected version.
+ # For example, typical systems have 'python' for version 2.* and 'python3'
+ # for version 3.*. So looking for names per dir will find, potentially,
+ # systematically 'python' (i.e. version 2) even if version 3 is searched.
+ if (WIN32)
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES python${_${_PYTHON_PREFIX}_VERSION}
+ python
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES})
+ else()
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES python${_${_PYTHON_PREFIX}_VERSION})
+ endif()
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
- # try using HINTS
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- python
- ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
- NAMES_PER_DIR
- HINTS ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
- # try using standard paths.
- if (WIN32)
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- python
- ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
- NAMES_PER_DIR)
- else()
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- NAMES_PER_DIR)
- endif()
+ # Apple frameworks handling
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_DEFAULT_PATH)
+ endif()
- # Apple frameworks handling
- if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- NAMES_PER_DIR
- PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
- PATH_SUFFIXES bin
- NO_DEFAULT_PATH)
- endif()
+ # Windows registry
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
+ PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ endif()
- # Windows registry
- if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endforeach()
+
+ if (NOT ${_PYTHON_PREFIX}_EXECUTABLE AND
+ NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ # No specific version found. Retry with generic names and standard paths.
+ # NAMES_PER_DIR is not defined on purpose to have a chance to find
+ # expected version.
+ # For example, typical systems have 'python' for version 2.* and 'python3'
+ # for version 3.*. So looking for names per dir will find, potentially,
+ # systematically 'python' (i.e. version 2) even if version 3 is searched.
find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_VERSION}
- python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+ NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
python
- ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
- NAMES_PER_DIR
- PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
- NO_DEFAULT_PATH)
- endif()
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES})
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION})
- if (${_PYTHON_PREFIX}_EXECUTABLE)
- break()
+ _python_validate_interpreter ()
endif()
- endforeach()
-
- if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
- # No specific version found. Retry with generic names
- # try using HINTS
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- python
- ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
- NAMES_PER_DIR
- HINTS ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
- # try using standard paths.
- # NAMES_PER_DIR is not defined on purpose to have a chance to find
- # expected version.
- # For example, typical systems have 'python' for version 2.* and 'python3'
- # for version 3.*. So looking for names per dir will find, potentially,
- # systematically 'python' (i.e. version 2) even if version 3 is searched.
- find_program (${_PYTHON_PREFIX}_EXECUTABLE
- NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
- python
- ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES})
-
- _python_validate_interpreter ()
endif()
# retrieve exact version of executable found
@@ -560,44 +811,98 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY)
endif()
- # try using root dir and registry
- foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
- if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ set (_${_PYTHON_PREFIX}_REGISTRY_PATHS)
+
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # Registry Paths
+ list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath])
+ endforeach()
+
+ while (TRUE)
+ if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_COMPILER
+ NAMES ipyc
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+
find_program (${_PYTHON_PREFIX}_COMPILER
NAMES ipyc
HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
- PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- endif()
+ _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION})
+ if (${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
- find_program (${_PYTHON_PREFIX}_COMPILER
- NAMES ipyc
- HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
+ if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_COMPILER
+ NAMES ipyc
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ endif()
+
+ break()
+ endwhile()
+ else()
+ # try using root dir and registry
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (${_PYTHON_PREFIX}_COMPILER
+ NAMES ipyc
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
- if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
find_program (${_PYTHON_PREFIX}_COMPILER
NAMES ipyc
- PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
- NO_DEFAULT_PATH)
- endif()
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION})
- if (${_PYTHON_PREFIX}_COMPILER)
- break()
- endif()
- endforeach()
+ if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (${_PYTHON_PREFIX}_COMPILER
+ NAMES ipyc
+ PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ if (${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ endforeach()
- # no specific version found, re-try in standard paths
- find_program (${_PYTHON_PREFIX}_COMPILER
- NAMES ipyc
- HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+ # no specific version found, re-try in standard paths
+ find_program (${_PYTHON_PREFIX}_COMPILER
+ NAMES ipyc
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+ endif()
if (${_PYTHON_PREFIX}_COMPILER)
# retrieve python environment version from compiler
@@ -685,39 +990,50 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
# if python interpreter is found, use its location and version to ensure consistency
# between interpreter and development environment
unset (_${_PYTHON_PREFIX}_PREFIX)
+ unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
+ unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
if (${_PYTHON_PREFIX}_Interpreter_FOUND)
execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.PREFIX)"
+ "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.EXEC_PREFIX)"
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
- OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_EXEC_PREFIX
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (_${_PYTHON_PREFIX}_RESULT)
- unset (_${_PYTHON_PREFIX}_PREFIX)
+ unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
endif()
- endif()
- set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
- foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
- string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
+ if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "STANDARD")
+ execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.BASE_EXEC_PREFIX)"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_BASE_EXEC_PREFIX
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
+ endif()
+ endif()
+ endif()
+ set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_EXEC_PREFIX}" "${_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
- # try to use pythonX.Y-config tool
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
set (_${_PYTHON_PREFIX}_CONFIG_NAMES)
- if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
- set (_${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config")
- endif()
- list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config")
+
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config")
+ endif()
+ list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config")
+ endforeach()
+
find_program (_${_PYTHON_PREFIX}_CONFIG
NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
PATH_SUFFIXES bin)
- unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
- if (NOT _${_PYTHON_PREFIX}_CONFIG)
- continue()
- endif()
- if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
# check that config tool match library architecture
execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
@@ -726,15 +1042,56 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (_${_PYTHON_PREFIX}_RESULT)
unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
- continue()
+ else()
+ string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+ if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
endif()
- string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
- if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
- unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
+ else()
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # try to use pythonX.Y-config tool
+ set (_${_PYTHON_PREFIX}_CONFIG_NAMES)
+ if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ set (_${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config")
+ endif()
+ list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config")
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin)
+ unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
+
+ if (NOT _${_PYTHON_PREFIX}_CONFIG)
continue()
endif()
- endif()
+ if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ # check that config tool match library architecture
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ continue()
+ endif()
+ string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+ if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ continue()
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ break()
+ endif()
+ endforeach()
+ endif()
+ if (_${_PYTHON_PREFIX}_CONFIG)
# retrieve root install directory
execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --prefix
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
@@ -744,9 +1101,15 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
if (_${_PYTHON_PREFIX}_RESULT)
# python-config is not usable
unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
- continue()
endif()
- set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+
+ unset (_${_PYTHON_PREFIX}_LIB_DIRS)
+ unset (_${_PYTHON_PREFIX}_PATH_SUFFIXES)
+ unset (_${_PYTHON_PREFIX}_LIB_NAMES)
# retrieve library
execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
@@ -758,33 +1121,58 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
# retrieve library directory
string (REGEX MATCHALL "-L[^ ]+" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_FLAGS}")
string (REPLACE "-L" "" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_LIB_DIRS}")
- list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_DIRS)
+ if (_${_PYTHON_PREFIX}_CONFIG MATCHES "python([0-9.]+)-config")
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${CMAKE_MATCH_1} LIBRARY)
+ endif()
+
# retrieve library name
string (REGEX MATCHALL "-lpython[^ ]+" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_FLAGS}")
string (REPLACE "-l" "" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_LIB_NAMES}")
list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_NAMES)
+ endif()
- find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
- NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
- NAMES_PER_DIR
- HINTS ${_${_PYTHON_PREFIX}_HINTS} ${_${_PYTHON_PREFIX}_LIB_DIRS}
- PATH_SUFFIXES lib
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
- # retrieve runtime library
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
- get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
- get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
- _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
- NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
- NAMES_PER_DIR
- HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES bin
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ list (APPEND _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
+ endif()
+ list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_DIRS)
+ list (APPEND _${_PYTHON_PREFIX}_HINTS ${_${_PYTHON_PREFIX}_LIB_DIRS})
+
+ if (NOT _${_PYTHON_PREFIX}_LIB_NAMES)
+ # config tool do not specify "-l" option (it is the case starting with 3.8)
+ # extract version from the config tool name and list all possible lib names
+ if (_${_PYTHON_PREFIX}_CONFIG MATCHES "python([0-9.]+)-config")
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${CMAKE_MATCH_1})
endif()
endif()
+ list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ # retrieve runtime library
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
# retrieve include directory
execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --includes
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
@@ -803,46 +1191,46 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
endif()
-
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_INCLUDE_DIR)
- break()
- endif()
- endforeach()
+ endif()
# Rely on HINTS and standard paths if config tool failed to locate artifacts
- if (NOT (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) OR NOT ${_PYTHON_PREFIX}_INCLUDE_DIR)
- foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
- string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
-
- _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
-
- set (_${_PYTHON_PREFIX}_REGISTRY_PATHS
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
+ if (NOT ${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT ${_PYTHON_PREFIX}_INCLUDE_DIR)
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ unset (_${_PYTHON_PREFIX}_LIB_NAMES)
+ unset (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG)
+ unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ unset (_${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ unset (_${_PYTHON_PREFIX}_PATH_SUFFIXES)
+
+ foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # library names
+ _python_get_lib_names (_${_PYTHON_PREFIX}_VERSION_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES})
+ _python_get_lib_names (_${_PYTHON_PREFIX}_VERSION_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION} DEBUG)
+ list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION_NAMES})
+
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ list (APPEND _${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS})
+
+ # Registry Paths
+ _python_get_registries (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS})
+
+ # Paths suffixes
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+ list (APPEND _${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_VERSION_PATHS})
+ endforeach()
if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
- python${_${_PYTHON_PREFIX}_VERSION}mu
- python${_${_PYTHON_PREFIX}_VERSION}m
- python${_${_PYTHON_PREFIX}_VERSION}u
- python${_${_PYTHON_PREFIX}_VERSION}
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
- PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_CMAKE_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
@@ -851,39 +1239,21 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
- python${_${_PYTHON_PREFIX}_VERSION}mu
- python${_${_PYTHON_PREFIX}_VERSION}m
- python${_${_PYTHON_PREFIX}_VERSION}u
- python${_${_PYTHON_PREFIX}_VERSION}
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
- PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
endif()
# search in HINTS locations
find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
- python${_${_PYTHON_PREFIX}_VERSION}mu
- python${_${_PYTHON_PREFIX}_VERSION}m
- python${_${_PYTHON_PREFIX}_VERSION}u
- python${_${_PYTHON_PREFIX}_VERSION}
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
@@ -901,42 +1271,29 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
# search in all default paths
find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
- python${_${_PYTHON_PREFIX}_VERSION}mu
- python${_${_PYTHON_PREFIX}_VERSION}m
- python${_${_PYTHON_PREFIX}_VERSION}u
- python${_${_PYTHON_PREFIX}_VERSION}
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
NAMES_PER_DIR
PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
- PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
- lib/python${_${_PYTHON_PREFIX}_VERSION}/config)
- # retrieve runtime library
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+
if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
- get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
- get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
- _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
- python${_${_PYTHON_PREFIX}_VERSION}mu
- python${_${_PYTHON_PREFIX}_VERSION}m
- python${_${_PYTHON_PREFIX}_VERSION}u
- python${_${_PYTHON_PREFIX}_VERSION}
- NAMES_PER_DIR
- HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES bin)
+ # extract version from library name
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "python([23])([0-9]+)")
+ set (_${_PYTHON_PREFIX}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
+ elseif (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "python([23])\\.([0-9]+)")
+ set (_${_PYTHON_PREFIX}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
+ endif()
endif()
if (WIN32)
# search for debug library
if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
# use library location as a hint
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION} DEBUG)
get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
NAMES_PER_DIR
HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
NO_DEFAULT_PATH)
@@ -944,7 +1301,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
# search first in known locations
if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
@@ -954,108 +1311,228 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
endif()
# search in all default paths
find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
NAMES_PER_DIR
HINTS ${_${_PYTHON_PREFIX}_HINTS}
PATHS ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
PATH_SUFFIXES lib libs)
- endif()
- if (${_PYTHON_PREFIX}_LIBRARY_DEBUG)
- get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY)
- get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
- _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
- NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
- NAMES_PER_DIR
- HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
- PATH_SUFFIXES bin)
+
+ # extract version from library name
+ if (${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "python([23])([0-9]+)")
+ set (_${_PYTHON_PREFIX}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
+ elseif (${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "python([23])\\.([0-9]+)")
+ set (_${_PYTHON_PREFIX}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
+ endif()
endif()
endif()
+ else()
+ foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_LIB_VERSION} DEBUG)
- # Don't search for include dir until library location is known
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
- unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION})
- if (${_PYTHON_PREFIX}_EXECUTABLE)
- # pick up include directory from configuration
- execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('include'))"
- RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
- OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PATH
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if (NOT _${_PYTHON_PREFIX}_RESULT)
- file (TO_CMAKE_PATH "${_${_PYTHON_PREFIX}_PATH}" _${_PYTHON_PREFIX}_PATH)
- list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PATH}")
- endif()
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
endif()
- foreach (_${_PYTHON_PREFIX}_LIB IN ITEMS ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
- if (${_${_PYTHON_PREFIX}_LIB})
- # Use the library's install prefix as a hint
- if (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
- list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
- elseif (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
- list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
- elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
- list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
- else()
- # assume library is in a directory under root
- get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${${_${_PYTHON_PREFIX}_LIB}}" DIRECTORY)
- get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
- list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+ # search in HINTS locations
+ find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ endif()
+
+ # search in all default paths
+ find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+
+ if (WIN32)
+ # search for debug library
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # use library location as a hint
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+ NO_DEFAULT_PATH)
+ else()
+ # search first in known locations
+ if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES lib libs
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
endif()
+ # search in all default paths
+ find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES lib libs)
endif()
- endforeach()
- list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_HINTS)
+ endif()
- if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
- find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
- NAMES Python.h
- HINTS ${_${_PYTHON_PREFIX}_HINTS}
- PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
- PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
- include/python${_${_PYTHON_PREFIX}_VERSION}m
- include/python${_${_PYTHON_PREFIX}_VERSION}u
- include/python${_${_PYTHON_PREFIX}_VERSION}
- include
- NO_CMAKE_PATH
- NO_CMAKE_ENVIRONMENT_PATH
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ break()
endif()
+ endforeach()
+ endif()
- if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
- find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
- NAMES Python.h
- HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
- PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
- PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
- include/python${_${_PYTHON_PREFIX}_VERSION}m
- include/python${_${_PYTHON_PREFIX}_VERSION}u
- include/python${_${_PYTHON_PREFIX}_VERSION}
- include
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH)
+ # retrieve runtime libraries
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_VERSION})
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin)
+ endif()
+ if (${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION} DEBUG)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin)
+ endif()
+
+ # Don't search for include dir if no library was founded
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
+
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ # pick up include directory from configuration
+ execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('include'))"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PATH
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ file (TO_CMAKE_PATH "${_${_PYTHON_PREFIX}_PATH}" _${_PYTHON_PREFIX}_PATH)
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PATH}")
+ endif()
+ endif()
+
+ foreach (_${_PYTHON_PREFIX}_LIB IN ITEMS ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ if (${_${_PYTHON_PREFIX}_LIB})
+ # Use the library's install prefix as a hint
+ if (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ elseif (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ else()
+ # assume library is in a directory under root
+ get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${${_${_PYTHON_PREFIX}_LIB}}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+ endif()
endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_HINTS)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_VERSION} INCLUDE)
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
NAMES Python.h
HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
- PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
- ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
- PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
- include/python${_${_PYTHON_PREFIX}_VERSION}m
- include/python${_${_PYTHON_PREFIX}_VERSION}u
- include/python${_${_PYTHON_PREFIX}_VERSION}
- include
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
endif()
- if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) AND ${_PYTHON_PREFIX}_INCLUDE_DIR)
- break()
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES Python.h
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
endif()
- endforeach()
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ endif()
+
+ find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES Python.h
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
# search header file in standard locations
find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
@@ -1198,72 +1675,104 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
endif()
if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
- AND ${_PYTHON_PREFIX}_Development_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::Python)
-
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
- OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
- OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
- set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
- else()
- set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
- endif()
+ AND ${_PYTHON_PREFIX}_Development_FOUND)
- add_library (${_PYTHON_PREFIX}::Python ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)
-
- set_property (TARGET ${_PYTHON_PREFIX}::Python
- PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
-
- if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
- OR (${_PYTHON_PREFIX}_LIBRARY_DEBUG AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG))
- # System manage shared libraries in two parts: import and runtime
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
- set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
- IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}"
- IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
- IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}"
- IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+ macro (__PYTHON_IMPORT_LIBRARY __name)
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
+ OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
+ OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+ set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
else()
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
- IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARY}"
- IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY}")
+ set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
endif()
- else()
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
- set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
- IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
- IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+
+ add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)
+
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
+
+ if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+ OR (${_PYTHON_PREFIX}_LIBRARY_DEBUG AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG))
+ # System manage shared libraries in two parts: import and runtime
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}"
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}"
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+ else()
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARY}"
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY}")
+ endif()
else()
- set_target_properties (${_PYTHON_PREFIX}::Python
- PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
- IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY}")
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+ else()
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY}")
+ endif()
endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC")
+ # extend link information with dependent libraries
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ string (REGEX MATCHALL "-[Ll][^ ]+" _${_PYTHON_PREFIX}_LINK_LIBRARIES "${_${_PYTHON_PREFIX}_FLAGS}")
+ # remove elements relative to python library itself
+ list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-lpython")
+ foreach (_${_PYTHON_PREFIX}_DIR IN LISTS ${_PYTHON_PREFIX}_LIBRARY_DIRS)
+ list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-L${${_PYTHON_PREFIX}_DIR}")
+ endforeach()
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})
+ endif()
+ endif()
+ endmacro()
+
+ if (NOT TARGET ${_PYTHON_PREFIX}::Python)
+ __python_import_library (${_PYTHON_PREFIX}::Python)
endif()
- if (_${_PYTHON_PREFIX}_CONFIG AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC")
- # extend link information with dependent libraries
- execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
- RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
- OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if (NOT _${_PYTHON_PREFIX}_RESULT)
- string (REGEX MATCHALL "-[Ll][^ ]+" _${_PYTHON_PREFIX}_LINK_LIBRARIES "${_${_PYTHON_PREFIX}_FLAGS}")
- # remove elements relative to python library itself
- list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-lpython")
- foreach (_${_PYTHON_PREFIX}_DIR IN LISTS ${_PYTHON_PREFIX}_LIBRARY_DIRS)
- list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-L${${_PYTHON_PREFIX}_DIR}")
- endforeach()
- set_property (TARGET ${_PYTHON_PREFIX}::Python
- PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})
+ if (NOT TARGET ${_PYTHON_PREFIX}::Module)
+ if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$")
+ # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python
+ # but ALIAS cannot be used because the imported library is not GLOBAL.
+ __python_import_library (${_PYTHON_PREFIX}::Module)
+ else()
+ add_library (${_PYTHON_PREFIX}::Module INTERFACE IMPORTED)
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
+
+ # When available, enforce shared library generation with undefined symbols
+ if (APPLE)
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok")
+ endif()
endif()
endif()
@@ -1273,7 +1782,7 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
#
function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name)
cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY
- "STATIC;SHARED;MODULE" "" "")
+ "STATIC;SHARED;MODULE" "" "")
unset (type)
if (NOT (PYTHON_ADD_LIBRARY_STATIC
@@ -1282,25 +1791,28 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
set (type MODULE)
endif()
add_library (${name} ${type} ${ARGN})
- target_link_libraries (${name} PRIVATE ${prefix}::Python)
- # customize library name to follow module name rules
get_property (type TARGET ${name} PROPERTY TYPE)
+
if (type STREQUAL "MODULE_LIBRARY")
+ target_link_libraries (${name} PRIVATE ${prefix}::Module)
+ # customize library name to follow module name rules
set_property (TARGET ${name} PROPERTY PREFIX "")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set_property (TARGET ${name} PROPERTY SUFFIX ".pyd")
endif()
+ else()
+ target_link_libraries (${name} PRIVATE ${prefix}::Python)
endif()
endfunction()
endif()
if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND
- AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Python)
+ AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module)
add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED)
set_property (TARGET ${_PYTHON_PREFIX}::NumPy
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
- target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Python)
+ target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module)
endif()
endif()
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index b9c0b6b73..8372ce74f 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -47,7 +47,11 @@ This module defines the following :ref:`Imported Targets <Imported Targets>`
``Python2::Compiler``
Python 2 compiler. Target defined if component ``Compiler`` is found.
``Python2::Python``
- Python 2 library. Target defined if component ``Development`` is found.
+ Python 2 library for Python embedding. Target defined if component
+ ``Development`` is found.
+``Python2::Module``
+ Python 2 library for Python module. Target defined if component
+ ``Development`` is found.
``Python2::NumPy``
NumPy library for Python 2. Target defined if component ``NumPy`` is found.
@@ -134,6 +138,19 @@ Hints
* If set to TRUE, search **only** for static libraries.
* If set to FALSE, search **only** for shared libraries.
+``Python2_FIND_STRATEGY``
+ This variable defines how lookup will be done.
+ The ``Python2_FIND_STRATEGY`` variable can be set to empty or one of the
+ following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
``Python2_FIND_REGISTRY``
On Windows the ``Python2_FIND_REGISTRY`` variable determine the order
of preference between registry and environment variables.
@@ -145,28 +162,45 @@ Hints
* ``LAST``: Try to use registry after environment variables.
* ``NEVER``: Never try to use registry.
-``CMAKE_FIND_FRAMEWORK``
- On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+``Python2_FIND_FRAMEWORK``
+ On macOS the ``Python2_FIND_FRAMEWORK`` variable determine the order of
preference between Apple-style and unix-style package components.
+ This variable can be set to empty or take same values as
+ :variable:`CMAKE_FIND_FRAMEWORK` variable.
.. note::
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+ If ``Python2_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python2_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ only when a virtual environment is active (i.e. the ``activate`` script has
+ been evaluated). In this case, it takes precedence over
+ ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+ The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or one of the
+ following:
- If a Python virtual environment is configured, set variable
- ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
- value ``LAST`` or ``NEVER`` to select it preferably.
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter. In this case, variable ``Python2_FIND_REGISTRY`` (Windows)
+ or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
Commands
^^^^^^^^
-This module defines the command ``Python2_add_library`` (when
+This module defines the command ``Python_add_library`` (when
:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
-:command:`add_library`, but takes care of Python module naming rules
-(only applied if library is of type ``MODULE``), and adds a dependency to target
-``Python2::Python``::
+:command:`add_library` and adds a dependency to target ``Python2::Python`` or,
+when library type is ``MODULE``, to target ``Python2::Module`` and takes care
+of Python module naming rules::
Python2_add_library (my_module MODULE src1.cpp)
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index c2f338469..2ead5b6a5 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -47,7 +47,11 @@ This module defines the following :ref:`Imported Targets <Imported Targets>`
``Python3::Compiler``
Python 3 compiler. Target defined if component ``Compiler`` is found.
``Python3::Python``
- Python 3 library. Target defined if component ``Development`` is found.
+ Python 3 library for Python embedding. Target defined if component
+ ``Development`` is found.
+``Python3::Module``
+ Python 3 library for Python module. Target defined if component
+ ``Development`` is found.
``Python3::NumPy``
NumPy library for Python 3. Target defined if component ``NumPy`` is found.
@@ -134,10 +138,23 @@ Hints
* If set to TRUE, search **only** for static libraries.
* If set to FALSE, search **only** for shared libraries.
+``Python3_FIND_STRATEGY``
+ This variable defines how lookup will be done.
+ The ``Python3_FIND_STRATEGY`` variable can be set to empty or one of the
+ following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
``Python3_FIND_REGISTRY``
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 empty or one of the
+ The ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
following:
* ``FIRST``: Try to use registry before environment variables.
@@ -145,28 +162,45 @@ Hints
* ``LAST``: Try to use registry after environment variables.
* ``NEVER``: Never try to use registry.
-``CMAKE_FIND_FRAMEWORK``
- On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+``Python3_FIND_FRAMEWORK``
+ On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of
preference between Apple-style and unix-style package components.
+ This variable can be set to empty or take same values as
+ :variable:`CMAKE_FIND_FRAMEWORK` variable.
.. note::
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+ If ``Python3_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python3_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ only when a virtual environment is active (i.e. the ``activate`` script has
+ been evaluated). In this case, it takes precedence over
+ ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+ The ``Python3_FIND_VIRTUALENV`` variable can be set to empty or one of the
+ following:
- If a Python virtual environment is configured, set variable
- ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
- value ``LAST`` or ``NEVER`` to select it preferably.
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter. In this case, variable ``Python3_FIND_REGISTRY`` (Windows)
+ or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
Commands
^^^^^^^^
-This module defines the command ``Python3_add_library`` (when
+This module defines the command ``Python_add_library`` (when
:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
-:command:`add_library`, but takes care of Python module naming rules
-(only applied if library is of type ``MODULE``), and adds a dependency to target
-``Python3::Python``::
+:command:`add_library` and adds a dependency to target ``Python3::Python`` or,
+when library type is ``MODULE``, to target ``Python3::Module`` and takes care
+of Python module naming rules::
Python3_add_library (my_module MODULE src1.cpp)
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
index 58debdd2a..7e01fbc98 100644
--- a/Modules/FindRuby.cmake
+++ b/Modules/FindRuby.cmake
@@ -49,14 +49,14 @@ set(_RUBY_POSSIBLE_EXECUTABLE_NAMES ruby)
# if 1.9 is required, don't look for ruby18 and ruby1.8, default to version 1.8
if(DEFINED Ruby_FIND_VERSION_MAJOR AND DEFINED Ruby_FIND_VERSION_MINOR)
- set(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${RUBY_FIND_VERSION_MINOR}")
- # we can't construct that if only major version is given
- set(_RUBY_POSSIBLE_EXECUTABLE_NAMES
- ruby${Ruby_FIND_VERSION_MAJOR}.${Ruby_FIND_VERSION_MINOR}
- ruby${Ruby_FIND_VERSION_MAJOR}${Ruby_FIND_VERSION_MINOR}
- ${_RUBY_POSSIBLE_EXECUTABLE_NAMES})
+ set(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${RUBY_FIND_VERSION_MINOR}")
+ # we can't construct that if only major version is given
+ set(_RUBY_POSSIBLE_EXECUTABLE_NAMES
+ ruby${Ruby_FIND_VERSION_MAJOR}.${Ruby_FIND_VERSION_MINOR}
+ ruby${Ruby_FIND_VERSION_MAJOR}${Ruby_FIND_VERSION_MINOR}
+ ${_RUBY_POSSIBLE_EXECUTABLE_NAMES})
else()
- set(Ruby_FIND_VERSION_SHORT_NODOT "18")
+ set(Ruby_FIND_VERSION_SHORT_NODOT "18")
endif()
if(NOT Ruby_FIND_VERSION_EXACT)
@@ -94,130 +94,131 @@ if(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
# query the ruby version
- _RUBY_CONFIG_VAR("MAJOR" RUBY_VERSION_MAJOR)
- _RUBY_CONFIG_VAR("MINOR" RUBY_VERSION_MINOR)
- _RUBY_CONFIG_VAR("TEENY" RUBY_VERSION_PATCH)
-
- # query the different directories
- _RUBY_CONFIG_VAR("archdir" RUBY_ARCH_DIR)
- _RUBY_CONFIG_VAR("arch" RUBY_ARCH)
- _RUBY_CONFIG_VAR("rubyhdrdir" RUBY_HDR_DIR)
- _RUBY_CONFIG_VAR("rubyarchhdrdir" RUBY_ARCHHDR_DIR)
- _RUBY_CONFIG_VAR("libdir" RUBY_POSSIBLE_LIB_DIR)
- _RUBY_CONFIG_VAR("rubylibdir" RUBY_RUBY_LIB_DIR)
-
- # site_ruby
- _RUBY_CONFIG_VAR("sitearchdir" RUBY_SITEARCH_DIR)
- _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR)
-
- # vendor_ruby available ?
- execute_process(COMMAND ${RUBY_EXECUTABLE} -r vendor-specific -e "print 'true'"
- OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY ERROR_QUIET)
-
- if(RUBY_HAS_VENDOR_RUBY)
- _RUBY_CONFIG_VAR("vendorlibdir" RUBY_VENDORLIB_DIR)
- _RUBY_CONFIG_VAR("vendorarchdir" RUBY_VENDORARCH_DIR)
- endif()
-
- # save the results in the cache so we don't have to run ruby the next time again
- set(RUBY_VERSION_MAJOR ${RUBY_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE)
- set(RUBY_VERSION_MINOR ${RUBY_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE)
- set(RUBY_VERSION_PATCH ${RUBY_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE)
- set(RUBY_ARCH_DIR ${RUBY_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE)
- set(RUBY_HDR_DIR ${RUBY_HDR_DIR} CACHE PATH "The Ruby header dir (1.9+)" FORCE)
- set(RUBY_ARCHHDR_DIR ${RUBY_ARCHHDR_DIR} CACHE PATH "The Ruby arch header dir (2.0+)" FORCE)
- set(RUBY_POSSIBLE_LIB_DIR ${RUBY_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
- set(RUBY_RUBY_LIB_DIR ${RUBY_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE)
- set(RUBY_SITEARCH_DIR ${RUBY_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE)
- set(RUBY_SITELIB_DIR ${RUBY_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE)
- set(RUBY_HAS_VENDOR_RUBY ${RUBY_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE)
- set(RUBY_VENDORARCH_DIR ${RUBY_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE)
- set(RUBY_VENDORLIB_DIR ${RUBY_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE)
-
- mark_as_advanced(
- RUBY_ARCH_DIR
- RUBY_ARCH
- RUBY_HDR_DIR
- RUBY_ARCHHDR_DIR
- RUBY_POSSIBLE_LIB_DIR
- RUBY_RUBY_LIB_DIR
- RUBY_SITEARCH_DIR
- RUBY_SITELIB_DIR
- RUBY_HAS_VENDOR_RUBY
- RUBY_VENDORARCH_DIR
- RUBY_VENDORLIB_DIR
- RUBY_VERSION_MAJOR
- RUBY_VERSION_MINOR
- RUBY_VERSION_PATCH
- )
+ _RUBY_CONFIG_VAR("MAJOR" RUBY_VERSION_MAJOR)
+ _RUBY_CONFIG_VAR("MINOR" RUBY_VERSION_MINOR)
+ _RUBY_CONFIG_VAR("TEENY" RUBY_VERSION_PATCH)
+
+ # query the different directories
+ _RUBY_CONFIG_VAR("archdir" RUBY_ARCH_DIR)
+ _RUBY_CONFIG_VAR("arch" RUBY_ARCH)
+ _RUBY_CONFIG_VAR("rubyhdrdir" RUBY_HDR_DIR)
+ _RUBY_CONFIG_VAR("rubyarchhdrdir" RUBY_ARCHHDR_DIR)
+ _RUBY_CONFIG_VAR("libdir" RUBY_POSSIBLE_LIB_DIR)
+ _RUBY_CONFIG_VAR("rubylibdir" RUBY_RUBY_LIB_DIR)
+
+ # site_ruby
+ _RUBY_CONFIG_VAR("sitearchdir" RUBY_SITEARCH_DIR)
+ _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR)
+
+ # vendor_ruby available ?
+ execute_process(COMMAND ${RUBY_EXECUTABLE} -r vendor-specific -e "print 'true'"
+ OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY ERROR_QUIET)
+
+ if(RUBY_HAS_VENDOR_RUBY)
+ _RUBY_CONFIG_VAR("vendorlibdir" RUBY_VENDORLIB_DIR)
+ _RUBY_CONFIG_VAR("vendorarchdir" RUBY_VENDORARCH_DIR)
+ endif()
+
+ # save the results in the cache so we don't have to run ruby the next time again
+ set(RUBY_VERSION_MAJOR ${RUBY_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE)
+ set(RUBY_VERSION_MINOR ${RUBY_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE)
+ set(RUBY_VERSION_PATCH ${RUBY_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE)
+ set(RUBY_ARCH_DIR ${RUBY_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE)
+ set(RUBY_HDR_DIR ${RUBY_HDR_DIR} CACHE PATH "The Ruby header dir (1.9+)" FORCE)
+ set(RUBY_ARCHHDR_DIR ${RUBY_ARCHHDR_DIR} CACHE PATH "The Ruby arch header dir (2.0+)" FORCE)
+ set(RUBY_POSSIBLE_LIB_DIR ${RUBY_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
+ set(RUBY_RUBY_LIB_DIR ${RUBY_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE)
+ set(RUBY_SITEARCH_DIR ${RUBY_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE)
+ set(RUBY_SITELIB_DIR ${RUBY_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE)
+ set(RUBY_HAS_VENDOR_RUBY ${RUBY_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE)
+ set(RUBY_VENDORARCH_DIR ${RUBY_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE)
+ set(RUBY_VENDORLIB_DIR ${RUBY_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE)
+
+ mark_as_advanced(
+ RUBY_ARCH_DIR
+ RUBY_ARCH
+ RUBY_HDR_DIR
+ RUBY_ARCHHDR_DIR
+ RUBY_POSSIBLE_LIB_DIR
+ RUBY_RUBY_LIB_DIR
+ RUBY_SITEARCH_DIR
+ RUBY_SITELIB_DIR
+ RUBY_HAS_VENDOR_RUBY
+ RUBY_VENDORARCH_DIR
+ RUBY_VENDORLIB_DIR
+ RUBY_VERSION_MAJOR
+ RUBY_VERSION_MINOR
+ RUBY_VERSION_PATCH
+ )
endif()
# In case RUBY_EXECUTABLE could not be executed (e.g. cross compiling)
# try to detect which version we found. This is not too good.
if(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
- # by default assume 1.8.0
- set(RUBY_VERSION_MAJOR 1)
- set(RUBY_VERSION_MINOR 8)
- set(RUBY_VERSION_PATCH 0)
- # check whether we found 1.9.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby1\\.?9")
- set(RUBY_VERSION_MAJOR 1)
- set(RUBY_VERSION_MINOR 9)
- endif()
- # check whether we found 2.0.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?0")
- set(RUBY_VERSION_MAJOR 2)
- set(RUBY_VERSION_MINOR 0)
- endif()
- # check whether we found 2.1.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?1")
- set(RUBY_VERSION_MAJOR 2)
- set(RUBY_VERSION_MINOR 1)
- endif()
- # check whether we found 2.2.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?2")
- set(RUBY_VERSION_MAJOR 2)
- set(RUBY_VERSION_MINOR 2)
- endif()
- # check whether we found 2.3.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?3")
- set(RUBY_VERSION_MAJOR 2)
- set(RUBY_VERSION_MINOR 3)
- endif()
- # check whether we found 2.4.x
- if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?4")
- set(RUBY_VERSION_MAJOR 2)
- set(RUBY_VERSION_MINOR 4)
- endif()
+ # by default assume 1.8.0
+ set(RUBY_VERSION_MAJOR 1)
+ set(RUBY_VERSION_MINOR 8)
+ set(RUBY_VERSION_PATCH 0)
+ # check whether we found 1.9.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby1\\.?9")
+ set(RUBY_VERSION_MAJOR 1)
+ set(RUBY_VERSION_MINOR 9)
+ endif()
+ # check whether we found 2.0.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?0")
+ set(RUBY_VERSION_MAJOR 2)
+ set(RUBY_VERSION_MINOR 0)
+ endif()
+ # check whether we found 2.1.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?1")
+ set(RUBY_VERSION_MAJOR 2)
+ set(RUBY_VERSION_MINOR 1)
+ endif()
+ # check whether we found 2.2.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?2")
+ set(RUBY_VERSION_MAJOR 2)
+ set(RUBY_VERSION_MINOR 2)
+ endif()
+ # check whether we found 2.3.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?3")
+ set(RUBY_VERSION_MAJOR 2)
+ set(RUBY_VERSION_MINOR 3)
+ endif()
+ # check whether we found 2.4.x
+ if(${RUBY_EXECUTABLE} MATCHES "ruby2\\.?4")
+ set(RUBY_VERSION_MAJOR 2)
+ set(RUBY_VERSION_MINOR 4)
+ endif()
endif()
if(RUBY_VERSION_MAJOR)
- set(RUBY_VERSION "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}")
- set(_RUBY_VERSION_SHORT "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}")
- set(_RUBY_VERSION_SHORT_NODOT "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}")
- set(_RUBY_NODOT_VERSION "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}")
+ set(RUBY_VERSION "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}")
+ set(_RUBY_VERSION_SHORT "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}")
+ set(_RUBY_VERSION_SHORT_NODOT "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}")
+ set(_RUBY_NODOT_VERSION "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}")
endif()
find_path(RUBY_INCLUDE_DIR
- NAMES ruby.h
- HINTS
- ${RUBY_HDR_DIR}
- ${RUBY_ARCH_DIR}
- /usr/lib/ruby/${_RUBY_VERSION_SHORT}/i586-linux-gnu/ )
+ NAMES ruby.h
+ HINTS
+ ${RUBY_HDR_DIR}
+ ${RUBY_ARCH_DIR}
+ /usr/lib/ruby/${_RUBY_VERSION_SHORT}/i586-linux-gnu/
+)
set(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIR} )
# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir
if( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18 OR "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18 OR RUBY_HDR_DIR)
- find_path(RUBY_CONFIG_INCLUDE_DIR
- NAMES ruby/config.h config.h
- HINTS
- ${RUBY_HDR_DIR}/${RUBY_ARCH}
- ${RUBY_ARCH_DIR}
- ${RUBY_ARCHHDR_DIR}
- )
-
- set(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIRS} ${RUBY_CONFIG_INCLUDE_DIR} )
+ find_path(RUBY_CONFIG_INCLUDE_DIR
+ NAMES ruby/config.h config.h
+ HINTS
+ ${RUBY_HDR_DIR}/${RUBY_ARCH}
+ ${RUBY_ARCH_DIR}
+ ${RUBY_ARCHHDR_DIR}
+ )
+
+ set(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIRS} ${RUBY_CONFIG_INCLUDE_DIR} )
endif()
@@ -225,33 +226,33 @@ endif()
set(_RUBY_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_RUBY_VERSION_SHORT} ruby${_RUBY_VERSION_SHORT_NODOT} ruby-${_RUBY_VERSION_SHORT} ruby-${RUBY_VERSION})
if(WIN32)
- set( _RUBY_MSVC_RUNTIME "" )
- if( MSVC_VERSION EQUAL 1200 )
- set( _RUBY_MSVC_RUNTIME "60" )
- endif()
- if( MSVC_VERSION EQUAL 1300 )
- set( _RUBY_MSVC_RUNTIME "70" )
- endif()
- if( MSVC_VERSION EQUAL 1310 )
- set( _RUBY_MSVC_RUNTIME "71" )
- endif()
- if( MSVC_VERSION EQUAL 1400 )
- set( _RUBY_MSVC_RUNTIME "80" )
- endif()
- if( MSVC_VERSION EQUAL 1500 )
- set( _RUBY_MSVC_RUNTIME "90" )
- endif()
-
- set(_RUBY_ARCH_PREFIX "")
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(_RUBY_ARCH_PREFIX "x64-")
- endif()
-
- list(APPEND _RUBY_POSSIBLE_LIB_NAMES
- "${_RUBY_ARCH_PREFIX}msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}"
- "${_RUBY_ARCH_PREFIX}msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}-static"
- "${_RUBY_ARCH_PREFIX}msvcrt-ruby${_RUBY_NODOT_VERSION}"
- "${_RUBY_ARCH_PREFIX}msvcrt-ruby${_RUBY_NODOT_VERSION}-static" )
+ set( _RUBY_MSVC_RUNTIME "" )
+ if( MSVC_VERSION EQUAL 1200 )
+ set( _RUBY_MSVC_RUNTIME "60" )
+ endif()
+ if( MSVC_VERSION EQUAL 1300 )
+ set( _RUBY_MSVC_RUNTIME "70" )
+ endif()
+ if( MSVC_VERSION EQUAL 1310 )
+ set( _RUBY_MSVC_RUNTIME "71" )
+ endif()
+ if( MSVC_VERSION EQUAL 1400 )
+ set( _RUBY_MSVC_RUNTIME "80" )
+ endif()
+ if( MSVC_VERSION EQUAL 1500 )
+ set( _RUBY_MSVC_RUNTIME "90" )
+ endif()
+
+ set(_RUBY_ARCH_PREFIX "")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_RUBY_ARCH_PREFIX "x64-")
+ endif()
+
+ list(APPEND _RUBY_POSSIBLE_LIB_NAMES
+ "${_RUBY_ARCH_PREFIX}msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}"
+ "${_RUBY_ARCH_PREFIX}msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}-static"
+ "${_RUBY_ARCH_PREFIX}msvcrt-ruby${_RUBY_NODOT_VERSION}"
+ "${_RUBY_ARCH_PREFIX}msvcrt-ruby${_RUBY_NODOT_VERSION}-static" )
endif()
find_library(RUBY_LIBRARY NAMES ${_RUBY_POSSIBLE_LIB_NAMES} HINTS ${RUBY_POSSIBLE_LIB_DIR} )
@@ -259,23 +260,23 @@ find_library(RUBY_LIBRARY NAMES ${_RUBY_POSSIBLE_LIB_NAMES} HINTS ${RUBY_POSSIBL
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
set(_RUBY_REQUIRED_VARS RUBY_EXECUTABLE RUBY_INCLUDE_DIR RUBY_LIBRARY)
if(_RUBY_VERSION_SHORT_NODOT GREATER 18)
- list(APPEND _RUBY_REQUIRED_VARS RUBY_CONFIG_INCLUDE_DIR)
+ list(APPEND _RUBY_REQUIRED_VARS RUBY_CONFIG_INCLUDE_DIR)
endif()
if(_RUBY_DEBUG_OUTPUT)
- message(STATUS "--------FindRuby.cmake debug------------")
- message(STATUS "_RUBY_POSSIBLE_EXECUTABLE_NAMES: ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}")
- message(STATUS "_RUBY_POSSIBLE_LIB_NAMES: ${_RUBY_POSSIBLE_LIB_NAMES}")
- message(STATUS "RUBY_ARCH_DIR: ${RUBY_ARCH_DIR}")
- message(STATUS "RUBY_HDR_DIR: ${RUBY_HDR_DIR}")
- message(STATUS "RUBY_POSSIBLE_LIB_DIR: ${RUBY_POSSIBLE_LIB_DIR}")
- message(STATUS "Found RUBY_VERSION: \"${RUBY_VERSION}\" , short: \"${_RUBY_VERSION_SHORT}\", nodot: \"${_RUBY_VERSION_SHORT_NODOT}\"")
- message(STATUS "_RUBY_REQUIRED_VARS: ${_RUBY_REQUIRED_VARS}")
- message(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}")
- message(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}")
- message(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}")
- message(STATUS "RUBY_CONFIG_INCLUDE_DIR: ${RUBY_CONFIG_INCLUDE_DIR}")
- message(STATUS "--------------------")
+ message(STATUS "--------FindRuby.cmake debug------------")
+ message(STATUS "_RUBY_POSSIBLE_EXECUTABLE_NAMES: ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}")
+ message(STATUS "_RUBY_POSSIBLE_LIB_NAMES: ${_RUBY_POSSIBLE_LIB_NAMES}")
+ message(STATUS "RUBY_ARCH_DIR: ${RUBY_ARCH_DIR}")
+ message(STATUS "RUBY_HDR_DIR: ${RUBY_HDR_DIR}")
+ message(STATUS "RUBY_POSSIBLE_LIB_DIR: ${RUBY_POSSIBLE_LIB_DIR}")
+ message(STATUS "Found RUBY_VERSION: \"${RUBY_VERSION}\" , short: \"${_RUBY_VERSION_SHORT}\", nodot: \"${_RUBY_VERSION_SHORT_NODOT}\"")
+ message(STATUS "_RUBY_REQUIRED_VARS: ${_RUBY_REQUIRED_VARS}")
+ message(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}")
+ message(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}")
+ message(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}")
+ message(STATUS "RUBY_CONFIG_INCLUDE_DIR: ${RUBY_CONFIG_INCLUDE_DIR}")
+ message(STATUS "--------------------")
endif()
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby REQUIRED_VARS ${_RUBY_REQUIRED_VARS}
diff --git a/Modules/FindSDL.cmake b/Modules/FindSDL.cmake
index 281383151..8d793a975 100644
--- a/Modules/FindSDL.cmake
+++ b/Modules/FindSDL.cmake
@@ -112,9 +112,6 @@ if(NOT SDL_BUILDING_LIBRARY)
ENV SDLDIR
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
PATHS
- /sw
- /opt/local
- /opt/csw
/opt
)
endif()
diff --git a/Modules/FindSDL_sound.cmake b/Modules/FindSDL_sound.cmake
index e2179811e..8d2f9f8fc 100644
--- a/Modules/FindSDL_sound.cmake
+++ b/Modules/FindSDL_sound.cmake
@@ -152,226 +152,199 @@ if(SDL_FOUND AND SDL_SOUND_INCLUDE_DIR AND SDL_SOUND_LIBRARY)
SDL_Quit();
return 0;
}"
- )
-
- # Calling
- # target_link_libraries(DetermineSoundLibs "${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
- # causes problems when SDL_LIBRARY looks like
- # /Library/Frameworks/SDL.framework;-framework Cocoa
- # The ;-framework Cocoa seems to be confusing CMake once the OS X
- # framework support was added. I was told that breaking up the list
- # would fix the problem.
- set(TMP_TRY_LIBS)
- foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
- string(APPEND TMP_TRY_LIBS " \"${lib}\"")
- endforeach()
-
- # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
-
- # Write the CMakeLists.txt and test project
- # Weird, this is still sketchy. If I don't quote the variables
- # in the TARGET_LINK_LIBRARIES, I seem to loose everything
- # in the SDL_LIBRARY string after the "-framework".
- # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
- file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
- "cmake_minimum_required(VERSION ${CMAKE_VERSION})
- project(DetermineSoundLibs)
- include_directories(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
- add_executable(DetermineSoundLibs DetermineSoundLibs.c)
- target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
- )
-
- try_compile(
- MY_RESULT
- ${PROJECT_BINARY_DIR}/CMakeTmp
- ${PROJECT_BINARY_DIR}/CMakeTmp
- DetermineSoundLibs
- OUTPUT_VARIABLE MY_OUTPUT
- )
-
- # message("${MY_RESULT}")
- # message(${MY_OUTPUT})
-
- if(NOT MY_RESULT)
-
- # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
- # I think Timidity is also compiled in statically.
- # I've never had to explcitly link against Quicktime, so I'll skip that for now.
-
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
-
- # Find MikMod
- if("${MY_OUTPUT}" MATCHES "MikMod_")
- find_library(MIKMOD_LIBRARY
- NAMES libmikmod-coreaudio mikmod
- PATHS
- ENV MIKMODDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(MIKMOD_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
- endif(MIKMOD_LIBRARY)
- endif("${MY_OUTPUT}" MATCHES "MikMod_")
-
- # Find ModPlug
- if("${MY_OUTPUT}" MATCHES "MODPLUG_")
- find_library(MODPLUG_LIBRARY
- NAMES modplug
- PATHS
- ENV MODPLUGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(MODPLUG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
- endif()
- endif()
-
-
- # Find Ogg and Vorbis
- if("${MY_OUTPUT}" MATCHES "ov_")
- find_library(VORBIS_LIBRARY
- NAMES vorbis Vorbis VORBIS
- PATHS
- ENV VORBISDIR
- ENV OGGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(VORBIS_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
- endif()
-
- find_library(OGG_LIBRARY
- NAMES ogg Ogg OGG
- PATHS
- ENV OGGDIR
- ENV VORBISDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(OGG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
- endif()
- endif()
-
-
- # Find SMPEG
- if("${MY_OUTPUT}" MATCHES "SMPEG_")
- find_library(SMPEG_LIBRARY
- NAMES smpeg SMPEG Smpeg SMpeg
- PATHS
- ENV SMPEGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(SMPEG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
- endif()
- endif()
-
-
- # Find FLAC
- if("${MY_OUTPUT}" MATCHES "FLAC_")
- find_library(FLAC_LIBRARY
- NAMES flac FLAC
- PATHS
- ENV FLACDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
- )
- if(FLAC_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
- endif()
- endif()
-
-
- # Hmmm...Speex seems to depend on Ogg. This might be a problem if
- # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
- # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
- # above for here or if two ogg entries will screw up things.
- if("${MY_OUTPUT}" MATCHES "speex_")
- find_library(SPEEX_LIBRARY
- NAMES speex SPEEX
- PATHS
- ENV SPEEXDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES
- lib
+ )
+
+ # Calling
+ # target_link_libraries(DetermineSoundLibs "${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ # causes problems when SDL_LIBRARY looks like
+ # /Library/Frameworks/SDL.framework;-framework Cocoa
+ # The ;-framework Cocoa seems to be confusing CMake once the OS X
+ # framework support was added. I was told that breaking up the list
+ # would fix the problem.
+ set(TMP_TRY_LIBS)
+ foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ string(APPEND TMP_TRY_LIBS " \"${lib}\"")
+ endforeach()
+
+
+ # Write the CMakeLists.txt and test project
+ # Weird, this is still sketchy. If I don't quote the variables
+ # in the TARGET_LINK_LIBRARIES, I seem to loose everything
+ # in the SDL_LIBRARY string after the "-framework".
+ # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
+ "cmake_minimum_required(VERSION ${CMAKE_VERSION})
+ project(DetermineSoundLibs)
+ include_directories(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
+ add_executable(DetermineSoundLibs DetermineSoundLibs.c)
+ target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
+ )
+
+ try_compile(
+ MY_RESULT
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ DetermineSoundLibs
+ OUTPUT_VARIABLE MY_OUTPUT
+ )
+
+
+ if(NOT MY_RESULT)
+
+ # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
+ # I think Timidity is also compiled in statically.
+ # I've never had to explcitly link against Quicktime, so I'll skip that for now.
+
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
+
+ # Find MikMod
+ if("${MY_OUTPUT}" MATCHES "MikMod_")
+ find_library(MIKMOD_LIBRARY
+ NAMES libmikmod-coreaudio mikmod
+ PATHS
+ ENV MIKMODDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MIKMOD_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
+ endif(MIKMOD_LIBRARY)
+ endif("${MY_OUTPUT}" MATCHES "MikMod_")
+
+ # Find ModPlug
+ if("${MY_OUTPUT}" MATCHES "MODPLUG_")
+ find_library(MODPLUG_LIBRARY
+ NAMES modplug
+ PATHS
+ ENV MODPLUGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MODPLUG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find Ogg and Vorbis
+ if("${MY_OUTPUT}" MATCHES "ov_")
+ find_library(VORBIS_LIBRARY
+ NAMES vorbis Vorbis VORBIS
+ PATHS
+ ENV VORBISDIR
+ ENV OGGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(VORBIS_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
+ endif()
+
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
)
- if(SPEEX_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
- endif()
-
- # Find OGG (needed for Speex)
- # We might have already found Ogg for Vorbis, so skip it if so.
- if(NOT OGG_LIBRARY)
- find_library(OGG_LIBRARY
- NAMES ogg Ogg OGG
- PATHS
- ENV OGGDIR
- ENV VORBISDIR
- ENV SPEEXDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(OGG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
- endif()
- endif()
- endif()
-
- set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP})
- else()
- set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY})
- endif()
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find SMPEG
+ if("${MY_OUTPUT}" MATCHES "SMPEG_")
+ find_library(SMPEG_LIBRARY
+ NAMES smpeg SMPEG Smpeg SMpeg
+ PATHS
+ ENV SMPEGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SMPEG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find FLAC
+ if("${MY_OUTPUT}" MATCHES "FLAC_")
+ find_library(FLAC_LIBRARY
+ NAMES flac FLAC
+ PATHS
+ ENV FLACDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(FLAC_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+ endif()
+ endif()
+
+
+ # Hmmm...Speex seems to depend on Ogg. This might be a problem if
+ # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
+ # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
+ # above for here or if two ogg entries will screw up things.
+ if("${MY_OUTPUT}" MATCHES "speex_")
+ find_library(SPEEX_LIBRARY
+ NAMES speex SPEEX
+ PATHS
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SPEEX_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+ endif()
+
+ # Find OGG (needed for Speex)
+ # We might have already found Ogg for Vorbis, so skip it if so.
+ if(NOT OGG_LIBRARY)
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+ endif()
+
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP})
+ else()
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY})
+ endif()
endif()
if(SDL_SOUND_INCLUDE_DIR AND EXISTS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h")
diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake
index 96b254f92..ae6ae56f7 100644
--- a/Modules/FindSWIG.cmake
+++ b/Modules/FindSWIG.cmake
@@ -5,13 +5,13 @@
FindSWIG
--------
-Find SWIG
+Find Simplified Wrapper and Interface Generator (SWIG)
This module finds an installed SWIG. It sets the following variables:
::
- SWIG_FOUND - set to true if SWIG is found
+ SWIG_FOUND - set to "True" if SWIG is found
SWIG_DIR - the directory where swig is installed
SWIG_EXECUTABLE - the path to the swig executable
SWIG_VERSION - the version number of the swig executable
@@ -19,11 +19,11 @@ This module finds an installed SWIG. It sets the following variables:
The minimum required version of SWIG can be specified using the
-standard syntax, e.g. find_package(SWIG 1.1)
+standard syntax, e.g. :command:`find_package(SWIG 1.1)`
-All information is collected from the SWIG_EXECUTABLE so the version
+All information is collected from the ``SWIG_EXECUTABLE``, so the version
to be found can be changed from the command line by means of setting
-SWIG_EXECUTABLE
+``SWIG_EXECUTABLE``
#]=======================================================================]
find_program(SWIG_EXECUTABLE NAMES swig4.0 swig3.0 swig2.0 swig)
@@ -64,4 +64,4 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWIG REQUIRED_VARS SWIG_EXECUTABLE SWIG_DIR
VERSION_VAR SWIG_VERSION )
-mark_as_advanced(SWIG_DIR SWIG_VERSION)
+mark_as_advanced(SWIG_DIR SWIG_VERSION SWIG_EXECUTABLE)
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
index 63ca936c4..00a3a415a 100644
--- a/Modules/FindTIFF.cmake
+++ b/Modules/FindTIFF.cmake
@@ -5,7 +5,7 @@
FindTIFF
--------
-Find the TIFF library (libtiff).
+Find the TIFF library (``libtiff``).
Imported targets
^^^^^^^^^^^^^^^^
diff --git a/Modules/FindTclsh.cmake b/Modules/FindTclsh.cmake
index e3bd11040..82be473b1 100644
--- a/Modules/FindTclsh.cmake
+++ b/Modules/FindTclsh.cmake
@@ -84,11 +84,11 @@ find_program(TCL_TCLSH
)
if(TCL_TCLSH)
- execute_process(COMMAND "${CMAKE_COMMAND}" -E echo puts "\$tcl_version"
- COMMAND "${TCL_TCLSH}"
- OUTPUT_VARIABLE TCLSH_VERSION_STRING
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E echo puts "\$tcl_version"
+ COMMAND "${TCL_TCLSH}"
+ OUTPUT_VARIABLE TCLSH_VERSION_STRING
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
index 36b55c274..b0c91b2ac 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -35,19 +35,42 @@ recommended for new code.
#]=======================================================================]
include (CheckLibraryExists)
-include (CheckSymbolExists)
set(Threads_FOUND FALSE)
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET ${Threads_FIND_QUIETLY})
if(CMAKE_C_COMPILER_LOADED)
include (CheckIncludeFile)
+ include (CheckCSourceCompiles)
elseif(CMAKE_CXX_COMPILER_LOADED)
include (CheckIncludeFileCXX)
+ include (CheckCXXSourceCompiles)
else()
message(FATAL_ERROR "FindThreads only works if either C or CXX language is enabled")
endif()
+# simple pthread test code
+set(PTHREAD_C_CXX_TEST_SOURCE [====[
+#include <pthread.h>
+
+void* test_func(void* data)
+{
+ return data;
+}
+
+int main(void)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, test_func, NULL);
+ pthread_detach(thread);
+ pthread_join(thread, NULL);
+ pthread_atfork(NULL, NULL, NULL);
+ pthread_exit(NULL);
+
+ return 0;
+}
+]====])
+
# Internal helper macro.
# Do NOT even think about using it outside of this file!
macro(_check_threads_lib LIBNAME FUNCNAME VARNAME)
@@ -106,8 +129,8 @@ if(CMAKE_C_COMPILER_LOADED)
else()
CHECK_INCLUDE_FILE_CXX("pthread.h" CMAKE_HAVE_PTHREAD_H)
endif()
-if(CMAKE_HAVE_PTHREAD_H)
+if(CMAKE_HAVE_PTHREAD_H)
#
# We have pthread.h
# Let's check for the library now.
@@ -115,13 +138,19 @@ if(CMAKE_HAVE_PTHREAD_H)
set(CMAKE_HAVE_THREADS_LIBRARY)
if(NOT THREADS_HAVE_PTHREAD_ARG)
# Check if pthread functions are in normal C library.
- CHECK_SYMBOL_EXISTS(pthread_create pthread.h CMAKE_HAVE_LIBC_CREATE)
- if(CMAKE_HAVE_LIBC_CREATE)
+ # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code.
+ # If the pthread functions already exist in C library, we could just use
+ # them instead of linking to the additional pthread library.
+ if(CMAKE_C_COMPILER_LOADED)
+ CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+ endif()
+ if(CMAKE_HAVE_LIBC_PTHREAD)
set(CMAKE_THREAD_LIBS_INIT "")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(Threads_FOUND TRUE)
else()
-
# Check for -pthread first if enabled. This is the recommended
# way, but not backwards compatible as one must also pass -pthread
# as compiler flag then.
@@ -129,6 +158,9 @@ if(CMAKE_HAVE_PTHREAD_H)
_check_pthreads_flag()
endif ()
+ if(CMAKE_SYSTEM MATCHES "GHS-MULTI")
+ _check_threads_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE)
+ endif()
_check_threads_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE)
_check_threads_lib(pthread pthread_create CMAKE_HAVE_PTHREAD_CREATE)
if(CMAKE_SYSTEM_NAME MATCHES "SunOS")
@@ -141,7 +173,7 @@ if(CMAKE_HAVE_PTHREAD_H)
_check_pthreads_flag()
endif()
-if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_CREATE)
+if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_PTHREAD)
set(CMAKE_USE_PTHREADS_INIT 1)
set(Threads_FOUND TRUE)
endif()
diff --git a/Modules/FindUnixCommands.cmake b/Modules/FindUnixCommands.cmake
index 3a735f79b..2513f5c29 100644
--- a/Modules/FindUnixCommands.cmake
+++ b/Modules/FindUnixCommands.cmake
@@ -7,8 +7,9 @@ FindUnixCommands
Find Unix commands, including the ones from Cygwin
-This module looks for the Unix commands bash, cp, gzip, mv, rm, and tar
-and stores the result in the variables BASH, CP, GZIP, MV, RM, and TAR.
+This module looks for the Unix commands ``bash``, ``cp``, ``gzip``,
+``mv``, ``rm``, and ``tar`` and stores the result in the variables
+``BASH``, ``CP``, ``GZIP``, ``MV``, ``RM``, and ``TAR``.
#]=======================================================================]
include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
index b1201b4ef..ae8d72dd9 100644
--- a/Modules/FindVulkan.cmake
+++ b/Modules/FindVulkan.cmake
@@ -5,7 +5,8 @@
FindVulkan
----------
-Try to find Vulkan
+Find Vulkan, which isis a low-overhead, cross-platform 3D graphics
+and computing API.
IMPORTED Targets
^^^^^^^^^^^^^^^^
@@ -18,7 +19,7 @@ Result Variables
This module defines the following variables::
- Vulkan_FOUND - True if Vulkan was found
+ Vulkan_FOUND - "True" if Vulkan was found
Vulkan_INCLUDE_DIRS - include directories for Vulkan
Vulkan_LIBRARIES - link against this library to use Vulkan
diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake
index 790eb423c..79e2313d5 100644
--- a/Modules/FindZLIB.cmake
+++ b/Modules/FindZLIB.cmake
@@ -67,8 +67,8 @@ set(_ZLIB_SEARCH_NORMAL
unset(_ZLIB_x86)
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
-set(ZLIB_NAMES z zlib zdll zlib1)
-set(ZLIB_NAMES_DEBUG zlibd zlibd1)
+set(ZLIB_NAMES z zlib zdll zlib1 zlibstatic)
+set(ZLIB_NAMES_DEBUG zd zlibd zdlld zlibd1 zlib1d zlibstaticd)
# Try each search configuration.
foreach(search ${_ZLIB_SEARCHES})
diff --git a/Modules/Findosg.cmake b/Modules/Findosg.cmake
index bb2845489..027f315cd 100644
--- a/Modules/Findosg.cmake
+++ b/Modules/Findosg.cmake
@@ -7,8 +7,6 @@ Findosg
-
-
NOTE: It is highly recommended that you use the new
FindOpenSceneGraph.cmake introduced in CMake 2.6.3 and not use this
Find module directly.
diff --git a/Modules/FindosgDB.cmake b/Modules/FindosgDB.cmake
index d0789badb..a28f65007 100644
--- a/Modules/FindosgDB.cmake
+++ b/Modules/FindosgDB.cmake
@@ -7,30 +7,38 @@ FindosgDB
-This is part of the Findosg* suite used to find OpenSceneGraph
+This is part of the ``Findosg*`` suite used to find OpenSceneGraph
components. Each component is separate and you must opt in to each
module. You must also opt into OpenGL and OpenThreads (and Producer
if needed) as these modules won't do it for you. This is to allow you
control over your own system piece by piece in case you need to opt
out of certain components or change the Find behavior for a particular
-module (perhaps because the default FindOpenGL.cmake module doesn't
+module (perhaps because the default :module:`FindOpenGL` module doesn't
work with your system as an example). If you want to use a more
convenient module that includes everything, use the
-FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+:module:`FindOpenSceneGraph` instead of the ``Findosg*.cmake`` modules.
-Locate osgDB This module defines
+Locate osgDB This module defines:
-OSGDB_FOUND - Was osgDB found? OSGDB_INCLUDE_DIR - Where to find the
-headers OSGDB_LIBRARIES - The libraries to link against for the osgDB
-(use this)
+``OSGDB_FOUND``
+ Was osgDB found?
-OSGDB_LIBRARY - The osgDB library OSGDB_LIBRARY_DEBUG - The osgDB
-debug library
+``OSGDB_INCLUDE_DIR``
+ Where to find the headers
-$OSGDIR is an environment variable that would correspond to the
-./configure --prefix=$OSGDIR used in building osg.
+``OSGDB_LIBRARIES``
+ The libraries to link against for the osgDB
+
+``OSGDB_LIBRARY``
+ The osgDB library
+
+``OSGDB_LIBRARY_DEBUG``
+ The osgDB debug library
+
+``$OSGDIR`` is an environment variable that would correspond to::
+
+ ./configure --prefix=$OSGDIR used in building osg.
-Created by Eric Wing.
#]=======================================================================]
# Header files are presumed to be included like
diff --git a/Modules/Findosg_functions.cmake b/Modules/Findosg_functions.cmake
index 40df4d5dd..563b6bd7a 100644
--- a/Modules/Findosg_functions.cmake
+++ b/Modules/Findosg_functions.cmake
@@ -20,19 +20,19 @@ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
# OSG_FIND_PATH
#
function(OSG_FIND_PATH module header)
- string(TOUPPER ${module} module_uc)
-
- # Try the user's environment request before anything else.
- find_path(${module_uc}_INCLUDE_DIR ${header}
- HINTS
- ENV ${module_uc}_DIR
- ENV OSG_DIR
- ENV OSGDIR
- ENV OSG_ROOT
- ${${module_uc}_DIR}
- ${OSG_DIR}
- PATH_SUFFIXES include
- )
+ string(TOUPPER ${module} module_uc)
+
+ # Try the user's environment request before anything else.
+ find_path(${module_uc}_INCLUDE_DIR ${header}
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES include
+ )
endfunction()
@@ -40,38 +40,38 @@ endfunction()
# OSG_FIND_LIBRARY
#
function(OSG_FIND_LIBRARY module library)
- string(TOUPPER ${module} module_uc)
-
- find_library(${module_uc}_LIBRARY_RELEASE
- NAMES ${library}
- HINTS
- ENV ${module_uc}_DIR
- ENV OSG_DIR
- ENV OSGDIR
- ENV OSG_ROOT
- ${${module_uc}_DIR}
- ${OSG_DIR}
- PATH_SUFFIXES lib
- )
-
- find_library(${module_uc}_LIBRARY_DEBUG
- NAMES ${library}d
- HINTS
- ENV ${module_uc}_DIR
- ENV OSG_DIR
- ENV OSGDIR
- ENV OSG_ROOT
- ${${module_uc}_DIR}
- ${OSG_DIR}
- PATH_SUFFIXES lib
- )
-
- select_library_configurations(${module_uc})
-
- # the variables set by select_library_configurations go out of scope
- # here, so we need to set them again
- set(${module_uc}_LIBRARY ${${module_uc}_LIBRARY} PARENT_SCOPE)
- set(${module_uc}_LIBRARIES ${${module_uc}_LIBRARIES} PARENT_SCOPE)
+ string(TOUPPER ${module} module_uc)
+
+ find_library(${module_uc}_LIBRARY_RELEASE
+ NAMES ${library}
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+ )
+
+ find_library(${module_uc}_LIBRARY_DEBUG
+ NAMES ${library}d
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+ )
+
+ select_library_configurations(${module_uc})
+
+ # the variables set by select_library_configurations go out of scope
+ # here, so we need to set them again
+ set(${module_uc}_LIBRARY ${${module_uc}_LIBRARY} PARENT_SCOPE)
+ set(${module_uc}_LIBRARIES ${${module_uc}_LIBRARIES} PARENT_SCOPE)
endfunction()
#
@@ -79,8 +79,8 @@ endfunction()
# Just a convenience function for calling MARK_AS_ADVANCED
#
function(OSG_MARK_AS_ADVANCED _module)
- string(TOUPPER ${_module} _module_UC)
- mark_as_advanced(${_module_UC}_INCLUDE_DIR)
- mark_as_advanced(${_module_UC}_LIBRARY)
- mark_as_advanced(${_module_UC}_LIBRARY_DEBUG)
+ string(TOUPPER ${_module} _module_UC)
+ mark_as_advanced(${_module_UC}_INCLUDE_DIR)
+ mark_as_advanced(${_module_UC}_LIBRARY)
+ mark_as_advanced(${_module_UC}_LIBRARY_DEBUG)
endfunction()
diff --git a/Modules/FortranCInterface/CMakeLists.txt b/Modules/FortranCInterface/CMakeLists.txt
index e3b81d7c3..381080bba 100644
--- a/Modules/FortranCInterface/CMakeLists.txt
+++ b/Modules/FortranCInterface/CMakeLists.txt
@@ -15,11 +15,11 @@ int main() { return 0; }
# List manglings of global symbol names to try.
set(global_symbols
my_sub # VisualAge
- my_sub_ # GNU, Intel, HP, SunPro, MIPSpro, PGI
+ my_sub_ # GNU, Intel, HP, SunPro, PGI
my_sub__ # GNU g77
MY_SUB # Intel on Windows
mysub # VisualAge
- mysub_ # GNU, Intel, HP, SunPro, MIPSpro, PGI
+ mysub_ # GNU, Intel, HP, SunPro, PGI
MYSUB # Intel on Windows
${FortranCInterface_GLOBAL_SYMBOLS}
)
@@ -48,7 +48,6 @@ set(module_symbols
list(REMOVE_DUPLICATES module_symbols)
# Note that some compiler manglings cannot be invoked from C:
-# MIPSpro uses "MY_SUB.in.MY_MODULE"
# SunPro uses "my_module.my_sub_"
# PathScale uses "MY_SUB.in.MY_MODULE"
diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake
index f2e452766..e4481f66d 100644
--- a/Modules/GenerateExportHeader.cmake
+++ b/Modules/GenerateExportHeader.cmake
@@ -7,7 +7,7 @@ GenerateExportHeader
Function for generation of export macros for libraries
-This module provides the function GENERATE_EXPORT_HEADER().
+This module provides the function ``GENERATE_EXPORT_HEADER()``.
The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file
suitable for preprocessor inclusion which contains EXPORT macros to be
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index fa6d75ae4..5be467621 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -169,17 +169,11 @@ Possible types are:
other
#]=======================================================================]
-function(gp_append_unique list_var value)
- set(contains 0)
-
- foreach(item ${${list_var}})
- if(item STREQUAL "${value}")
- set(contains 1)
- break()
- endif()
- endforeach()
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
- if(NOT contains)
+function(gp_append_unique list_var value)
+ if(NOT value IN_LIST ${list_var})
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
endif()
endfunction()
@@ -1043,3 +1037,5 @@ function(list_prerequisites_by_glob glob_arg glob_exp)
endif()
endforeach()
endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/Internal/CPack/CPackNuGet.cmake b/Modules/Internal/CPack/CPackNuGet.cmake
index 198ccad59..4b2ce9248 100644
--- a/Modules/Internal/CPack/CPackNuGet.cmake
+++ b/Modules/Internal/CPack/CPackNuGet.cmake
@@ -276,7 +276,7 @@ function(_cpack_nuget_make_files_tag)
set(_CPACK_NUGET_FILES_TAG "<files>\n${_files} </files>" PARENT_SCOPE)
endfunction()
-find_program(NUGET_EXECUTABLE NuGet)
+find_program(NUGET_EXECUTABLE nuget)
_cpack_nuget_debug_var(NUGET_EXECUTABLE)
if(NOT NUGET_EXECUTABLE)
message(FATAL_ERROR "NuGet executable not found")
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
index 2de71ee20..ffb24e2d9 100644
--- a/Modules/Internal/CPack/CPackRPM.cmake
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -63,6 +63,11 @@ function(get_unix_permissions_octal_notation PERMISSIONS_VAR RETURN_VAR)
set(${RETURN_VAR} "${OWNER_PERMISSIONS}${GROUP_PERMISSIONS}${WORLD_PERMISSIONS}" PARENT_SCOPE)
endfunction()
+function(cpack_rpm_exact_regex regex_var string)
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${string}")
+ set("${regex_var}" "${regex}" PARENT_SCOPE)
+endfunction()
+
function(cpack_rpm_prepare_relocation_paths)
# set appropriate prefix, remove possible trailing slash and convert backslashes to slashes
if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX)
@@ -482,7 +487,9 @@ function(cpack_rpm_prepare_install_files INSTALL_FILES_LIST WDIR PACKAGE_PREFIXE
# recalculate path length after conversion to canonical form
string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
- if(SYMLINK_POINT_ MATCHES "${WDIR}/.*")
+ cpack_rpm_exact_regex(IN_SYMLINK_POINT_REGEX "${WDIR}")
+ string(APPEND IN_SYMLINK_POINT_REGEX "/.*")
+ if(SYMLINK_POINT_ MATCHES "${IN_SYMLINK_POINT_REGEX}")
# only symlinks that are pointing inside the packaging structure should be checked for relocation
string(SUBSTRING "${SYMLINK_POINT_}" ${WDR_LEN_} -1 SYMLINK_POINT_WD_)
cpack_rpm_symlink_get_relocation_prefixes("${F}" "${PACKAGE_PREFIXES}" "SYMLINK_RELOCATIONS")
@@ -1151,7 +1158,9 @@ function(cpack_rpm_generate_package)
# Now we may create the RPM build tree structure
set(CPACK_RPM_ROOTDIR "${CPACK_TOPLEVEL_DIRECTORY}")
- message(STATUS "CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=${CPACK_RPM_ROOTDIR}")
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=${CPACK_RPM_ROOTDIR}")
+ endif()
# Prepare RPM build tree
file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR})
file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/tmp)
diff --git a/Modules/Internal/FeatureTesting.cmake b/Modules/Internal/FeatureTesting.cmake
index de336e708..75be473f3 100644
--- a/Modules/Internal/FeatureTesting.cmake
+++ b/Modules/Internal/FeatureTesting.cmake
@@ -71,10 +71,35 @@ endmacro()
macro(_record_compiler_features_c std)
list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
- _record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+
+ get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_C${std}_KNOWN_FEATURES)
+ if(lang_level_has_features)
+ _record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+ endif()
+ unset(lang_level_has_features)
endmacro()
macro(_record_compiler_features_cxx std)
list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
- _record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+
+ get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_CXX${std}_KNOWN_FEATURES)
+ if(lang_level_has_features)
+ _record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+ endif()
+ unset(lang_level_has_features)
+endmacro()
+
+macro(_has_compiler_features lang level compile_flags feature_list)
+ # presume all known features are supported
+ get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+ list(APPEND ${feature_list} ${known_features})
+endmacro()
+
+macro(_has_compiler_features_c std)
+ list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
+ _has_compiler_features(C ${std} "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+endmacro()
+macro(_has_compiler_features_cxx std)
+ list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
+ _has_compiler_features(CXX ${std} "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
endmacro()
diff --git a/Modules/KDE3Macros.cmake b/Modules/KDE3Macros.cmake
index b3f31ed62..1c353ba84 100644
--- a/Modules/KDE3Macros.cmake
+++ b/Modules/KDE3Macros.cmake
@@ -26,105 +26,106 @@ include(AddFileDependencies)
#create the kidl and skeletion file for dcop stuff
#usage: KDE_ADD_COP_SKELS(foo_SRCS ${dcop_headers})
macro(KDE3_ADD_DCOP_SKELS _sources)
- foreach (_current_FILE ${ARGN})
+ foreach (_current_FILE ${ARGN})
- get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
- get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
- set(_skel ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_skel.cpp)
- set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
+ set(_skel ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_skel.cpp)
+ set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
- if (NOT HAVE_${_basename}_KIDL_RULE)
- set(HAVE_${_basename}_KIDL_RULE ON)
+ if (NOT HAVE_${_basename}_KIDL_RULE)
+ set(HAVE_${_basename}_KIDL_RULE ON)
- add_custom_command(OUTPUT ${_kidl}
- COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
- ARGS ${_tmp_FILE} > ${_kidl}
- DEPENDS ${_tmp_FILE}
- )
+ add_custom_command(OUTPUT ${_kidl}
+ COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
+ ARGS ${_tmp_FILE} > ${_kidl}
+ DEPENDS ${_tmp_FILE}
+ )
- endif ()
+ endif ()
- if (NOT HAVE_${_basename}_SKEL_RULE)
- set(HAVE_${_basename}_SKEL_RULE ON)
+ if (NOT HAVE_${_basename}_SKEL_RULE)
+ set(HAVE_${_basename}_SKEL_RULE ON)
- add_custom_command(OUTPUT ${_skel}
- COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
- ARGS --c++-suffix cpp --no-signals --no-stub ${_kidl}
- DEPENDS ${_kidl}
- )
+ add_custom_command(OUTPUT ${_skel}
+ COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
+ ARGS --c++-suffix cpp --no-signals --no-stub ${_kidl}
+ DEPENDS ${_kidl}
+ )
- endif ()
+ endif ()
- set(${_sources} ${${_sources}} ${_skel})
+ set(${_sources} ${${_sources}} ${_skel})
- endforeach ()
+ endforeach ()
endmacro()
macro(KDE3_ADD_DCOP_STUBS _sources)
- foreach (_current_FILE ${ARGN})
+ foreach (_current_FILE ${ARGN})
- get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
- get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
- set(_stub_CPP ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_stub.cpp)
- set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
+ set(_stub_CPP ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_stub.cpp)
+ set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
- if (NOT HAVE_${_basename}_KIDL_RULE)
- set(HAVE_${_basename}_KIDL_RULE ON)
+ if (NOT HAVE_${_basename}_KIDL_RULE)
+ set(HAVE_${_basename}_KIDL_RULE ON)
- add_custom_command(OUTPUT ${_kidl}
- COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
- ARGS ${_tmp_FILE} > ${_kidl}
- DEPENDS ${_tmp_FILE}
- )
+ add_custom_command(OUTPUT ${_kidl}
+ COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
+ ARGS ${_tmp_FILE} > ${_kidl}
+ DEPENDS ${_tmp_FILE}
+ )
- endif ()
+ endif ()
- if (NOT HAVE_${_basename}_STUB_RULE)
- set(HAVE_${_basename}_STUB_RULE ON)
+ if (NOT HAVE_${_basename}_STUB_RULE)
+ set(HAVE_${_basename}_STUB_RULE ON)
- add_custom_command(OUTPUT ${_stub_CPP}
- COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
- ARGS --c++-suffix cpp --no-signals --no-skel ${_kidl}
- DEPENDS ${_kidl}
- )
+ add_custom_command(OUTPUT ${_stub_CPP}
+ COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
+ ARGS --c++-suffix cpp --no-signals --no-skel ${_kidl}
+ DEPENDS ${_kidl}
+ )
- endif ()
+ endif ()
- set(${_sources} ${${_sources}} ${_stub_CPP})
+ set(${_sources} ${${_sources}} ${_stub_CPP})
- endforeach ()
+ endforeach ()
endmacro()
macro(KDE3_ADD_KCFG_FILES _sources)
- foreach (_current_FILE ${ARGN})
+ foreach (_current_FILE ${ARGN})
- get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
- get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
- file(READ ${_tmp_FILE} _contents)
- string(REGEX REPLACE "^(.*\n)?File=([^\n]+)\n.*$" "\\2" _kcfg_FILE "${_contents}")
+ file(READ ${_tmp_FILE} _contents)
+ string(REGEX REPLACE "^(.*\n)?File=([^\n]+)\n.*$" "\\2" _kcfg_FILE "${_contents}")
- set(_src_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
- set(_header_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
+ set(_src_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
+ set(_header_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
- add_custom_command(OUTPUT ${_src_FILE}
- COMMAND ${KDE3_KCFGC_EXECUTABLE}
- ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE} ${_tmp_FILE}
- DEPENDS ${_tmp_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE} )
+ add_custom_command(OUTPUT ${_src_FILE}
+ COMMAND ${KDE3_KCFGC_EXECUTABLE}
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE} ${_tmp_FILE}
+ DEPENDS ${_tmp_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE}
+ )
- set(${_sources} ${${_sources}} ${_src_FILE})
+ set(${_sources} ${${_sources}} ${_src_FILE})
- endforeach ()
+ endforeach ()
endmacro()
@@ -132,22 +133,22 @@ endmacro()
#create the moc files and add them to the list of sources
#usage: KDE_ADD_MOC_FILES(foo_SRCS ${moc_headers})
macro(KDE3_ADD_MOC_FILES _sources)
- foreach (_current_FILE ${ARGN})
+ foreach (_current_FILE ${ARGN})
- get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
- get_filename_component(_basename ${_tmp_FILE} NAME_WE)
- set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
- add_custom_command(OUTPUT ${_moc}
- COMMAND ${QT_MOC_EXECUTABLE}
- ARGS ${_tmp_FILE} -o ${_moc}
- DEPENDS ${_tmp_FILE}
- )
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_tmp_FILE} -o ${_moc}
+ DEPENDS ${_tmp_FILE}
+ )
- set(${_sources} ${${_sources}} ${_moc})
+ set(${_sources} ${${_sources}} ${_moc})
- endforeach ()
+ endforeach ()
endmacro()
@@ -156,186 +157,186 @@ get_filename_component( KDE3_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
#create the implementation files from the ui files and add them to the list of sources
#usage: KDE_ADD_UI_FILES(foo_SRCS ${ui_files})
macro(KDE3_ADD_UI_FILES _sources )
- foreach (_current_FILE ${ARGN})
-
- get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
-
- get_filename_component(_basename ${_tmp_FILE} NAME_WE)
- set(_header ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
- set(_src ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
- set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
-
- add_custom_command(OUTPUT ${_header}
- COMMAND ${QT_UIC_EXECUTABLE}
- ARGS -L ${KDE3_LIB_DIR}/kde3/plugins/designer -nounload -o ${_header} ${CMAKE_CURRENT_SOURCE_DIR}/${_current_FILE}
- DEPENDS ${_tmp_FILE}
- )
-
- add_custom_command(OUTPUT ${_src}
- COMMAND ${CMAKE_COMMAND}
- ARGS
- -DKDE_UIC_PLUGIN_DIR:FILEPATH=${KDE3_LIB_DIR}/kde3/plugins/designer
- -DKDE_UIC_EXECUTABLE:FILEPATH=${QT_UIC_EXECUTABLE}
- -DKDE_UIC_FILE:FILEPATH=${_tmp_FILE}
- -DKDE_UIC_CPP_FILE:FILEPATH=${_src}
- -DKDE_UIC_H_FILE:FILEPATH=${_header}
- -P ${KDE3_MODULE_DIR}/kde3uic.cmake
- DEPENDS ${_header}
- )
-
- add_custom_command(OUTPUT ${_moc}
- COMMAND ${QT_MOC_EXECUTABLE}
- ARGS ${_header} -o ${_moc}
- DEPENDS ${_header}
- )
-
- set(${_sources} ${${_sources}} ${_src} ${_moc} )
-
- endforeach ()
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ set(_header ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
+ set(_src ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
+
+ add_custom_command(OUTPUT ${_header}
+ COMMAND ${QT_UIC_EXECUTABLE}
+ ARGS -L ${KDE3_LIB_DIR}/kde3/plugins/designer -nounload -o ${_header} ${CMAKE_CURRENT_SOURCE_DIR}/${_current_FILE}
+ DEPENDS ${_tmp_FILE}
+ )
+
+ add_custom_command(OUTPUT ${_src}
+ COMMAND ${CMAKE_COMMAND}
+ ARGS
+ -DKDE_UIC_PLUGIN_DIR:FILEPATH=${KDE3_LIB_DIR}/kde3/plugins/designer
+ -DKDE_UIC_EXECUTABLE:FILEPATH=${QT_UIC_EXECUTABLE}
+ -DKDE_UIC_FILE:FILEPATH=${_tmp_FILE}
+ -DKDE_UIC_CPP_FILE:FILEPATH=${_src}
+ -DKDE_UIC_H_FILE:FILEPATH=${_header}
+ -P ${KDE3_MODULE_DIR}/kde3uic.cmake
+ DEPENDS ${_header}
+ )
+
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_header} -o ${_moc}
+ DEPENDS ${_header}
+ )
+
+ set(${_sources} ${${_sources}} ${_src} ${_moc} )
+
+ endforeach ()
endmacro()
macro(KDE3_AUTOMOC)
- set(_matching_FILES )
- foreach (_current_FILE ${ARGN})
+ set(_matching_FILES )
+ foreach (_current_FILE ${ARGN})
- get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
- # if "SKIP_AUTOMOC" is set to true, we will not handle this file here.
- # here. this is required to make bouic work correctly:
- # we need to add generated .cpp files to the sources (to compile them),
- # but we cannot let automoc handle them, as the .cpp files don't exist yet when
- # cmake is run for the very first time on them -> however the .cpp files might
- # exist at a later run. at that time we need to skip them, so that we don't add two
- # different rules for the same moc file
- get_source_file_property(_skip ${_abs_FILE} SKIP_AUTOMOC)
+ # if "SKIP_AUTOMOC" is set to true, we will not handle this file here.
+ # here. this is required to make bouic work correctly:
+ # we need to add generated .cpp files to the sources (to compile them),
+ # but we cannot let automoc handle them, as the .cpp files don't exist yet when
+ # cmake is run for the very first time on them -> however the .cpp files might
+ # exist at a later run. at that time we need to skip them, so that we don't add two
+ # different rules for the same moc file
+ get_source_file_property(_skip ${_abs_FILE} SKIP_AUTOMOC)
- if (EXISTS ${_abs_FILE} AND NOT _skip)
+ if (EXISTS ${_abs_FILE} AND NOT _skip)
- file(STRINGS ${_abs_FILE} _match REGEX "#include +[^ ]+\\.moc[\">]")
+ file(STRINGS ${_abs_FILE} _match REGEX "#include +[^ ]+\\.moc[\">]")
- get_filename_component(_abs_PATH ${_abs_FILE} PATH)
+ get_filename_component(_abs_PATH ${_abs_FILE} PATH)
- foreach (_current_MOC_INC IN LISTS _match)
- string(REGEX MATCH "[^ <\"]+\\.moc" _current_MOC "${_current_MOC_INC}")
+ foreach (_current_MOC_INC IN LISTS _match)
+ string(REGEX MATCH "[^ <\"]+\\.moc" _current_MOC "${_current_MOC_INC}")
- get_filename_component(_basename ${_current_MOC} NAME_WE)
-# set(_header ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h)
- set(_header ${_abs_PATH}/${_basename}.h)
- set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC})
+ get_filename_component(_basename ${_current_MOC} NAME_WE)
+# set(_header ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h)
+ set(_header ${_abs_PATH}/${_basename}.h)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC})
- add_custom_command(OUTPUT ${_moc}
- COMMAND ${QT_MOC_EXECUTABLE}
- ARGS ${_header} -o ${_moc}
- DEPENDS ${_header}
- )
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_header} -o ${_moc}
+ DEPENDS ${_header}
+ )
- ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc})
+ ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc})
- endforeach ()
- unset(_match)
- unset(_header)
- unset(_moc)
- endif ()
- endforeach ()
+ endforeach ()
+ unset(_match)
+ unset(_header)
+ unset(_moc)
+ endif ()
+ endforeach ()
endmacro()
# only used internally by KDE3_INSTALL_ICONS
macro (_KDE3_ADD_ICON_INSTALL_RULE _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME)
- # if the string doesn't match the pattern, the result is the full string, so all three have the same content
- if (NOT ${_group} STREQUAL ${_install_NAME} )
- set(_icon_GROUP "actions")
+ # if the string doesn't match the pattern, the result is the full string, so all three have the same content
+ if (NOT ${_group} STREQUAL ${_install_NAME} )
+ set(_icon_GROUP "actions")
- if (${_group} STREQUAL "mime")
- set(_icon_GROUP "mimetypes")
- endif ()
+ if (${_group} STREQUAL "mime")
+ set(_icon_GROUP "mimetypes")
+ endif ()
- if (${_group} STREQUAL "filesys")
- set(_icon_GROUP "filesystems")
- endif ()
+ if (${_group} STREQUAL "filesys")
+ set(_icon_GROUP "filesystems")
+ endif ()
- if (${_group} STREQUAL "device")
- set(_icon_GROUP "devices")
- endif ()
+ if (${_group} STREQUAL "device")
+ set(_icon_GROUP "devices")
+ endif ()
- if (${_group} STREQUAL "app")
- set(_icon_GROUP "apps")
- endif ()
+ if (${_group} STREQUAL "app")
+ set(_icon_GROUP "apps")
+ endif ()
- if (${_group} STREQUAL "action")
- set(_icon_GROUP "actions")
- endif ()
+ if (${_group} STREQUAL "action")
+ set(_icon_GROUP "actions")
+ endif ()
-# message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name}" )
- install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/ RENAME ${_install_NAME} )
- endif ()
+ # message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name}" )
+ install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/ RENAME ${_install_NAME} )
+ endif ()
endmacro ()
macro (KDE3_INSTALL_ICONS _theme )
- set(_defaultpath "${CMAKE_INSTALL_PREFIX}/share/icons")
- # first the png icons
- file(GLOB _icons *.png)
- foreach (_current_ICON ${_icons} )
- string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\1" _size "${_current_ICON}")
- string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\2" _group "${_current_ICON}")
- string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\3" _name "${_current_ICON}")
- _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
- ${_defaultpath}/${_theme}/${_size}x${_size}
- ${_group} ${_current_ICON} ${_name})
- endforeach ()
-
- # and now the svg icons
- file(GLOB _icons *.svgz)
- foreach (_current_ICON ${_icons} )
- string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\1" _group "${_current_ICON}")
- string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\2" _name "${_current_ICON}")
- _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
- ${_defaultpath}/${_theme}/scalable
- ${_group} ${_current_ICON} ${_name})
- endforeach ()
+ set(_defaultpath "${CMAKE_INSTALL_PREFIX}/share/icons")
+ # first the png icons
+ file(GLOB _icons *.png)
+ foreach (_current_ICON ${_icons} )
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\1" _size "${_current_ICON}")
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\2" _group "${_current_ICON}")
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\3" _name "${_current_ICON}")
+ _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
+ ${_defaultpath}/${_theme}/${_size}x${_size}
+ ${_group} ${_current_ICON} ${_name})
+ endforeach ()
+
+ # and now the svg icons
+ file(GLOB _icons *.svgz)
+ foreach (_current_ICON ${_icons} )
+ string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\1" _group "${_current_ICON}")
+ string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\2" _name "${_current_ICON}")
+ _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
+ ${_defaultpath}/${_theme}/scalable
+ ${_group} ${_current_ICON} ${_name})
+ endforeach ()
endmacro ()
macro(KDE3_INSTALL_LIBTOOL_FILE _target)
- get_target_property(_target_location ${_target} LOCATION)
-
- get_filename_component(_laname ${_target_location} NAME_WE)
- get_filename_component(_soname ${_target_location} NAME)
- set(_laname ${CMAKE_CURRENT_BINARY_DIR}/${_laname}.la)
-
- file(WRITE ${_laname} "# ${_laname} - a libtool library file, generated by cmake \n")
- file(APPEND ${_laname} "# The name that we can dlopen(3).\n")
- file(APPEND ${_laname} "dlname='${_soname}'\n")
- file(APPEND ${_laname} "# Names of this library\n")
- if(CYGWIN)
- file(APPEND ${_laname} "library_names='${_soname}'\n")
- else()
- file(APPEND ${_laname} "library_names='${_soname} ${_soname} ${_soname}'\n")
- endif()
- file(APPEND ${_laname} "# The name of the static archive\n")
- file(APPEND ${_laname} "old_library=''\n")
- file(APPEND ${_laname} "# Libraries that this one depends upon.\n")
- file(APPEND ${_laname} "dependency_libs=''\n")
+ get_target_property(_target_location ${_target} LOCATION)
+
+ get_filename_component(_laname ${_target_location} NAME_WE)
+ get_filename_component(_soname ${_target_location} NAME)
+ set(_laname ${CMAKE_CURRENT_BINARY_DIR}/${_laname}.la)
+
+ file(WRITE ${_laname} "# ${_laname} - a libtool library file, generated by cmake \n")
+ file(APPEND ${_laname} "# The name that we can dlopen(3).\n")
+ file(APPEND ${_laname} "dlname='${_soname}'\n")
+ file(APPEND ${_laname} "# Names of this library\n")
+ if(CYGWIN)
+ file(APPEND ${_laname} "library_names='${_soname}'\n")
+ else()
+ file(APPEND ${_laname} "library_names='${_soname} ${_soname} ${_soname}'\n")
+ endif()
+ file(APPEND ${_laname} "# The name of the static archive\n")
+ file(APPEND ${_laname} "old_library=''\n")
+ file(APPEND ${_laname} "# Libraries that this one depends upon.\n")
+ file(APPEND ${_laname} "dependency_libs=''\n")
# file(APPEND ${_laname} "dependency_libs='${${_target}_LIB_DEPENDS}'\n")
- file(APPEND ${_laname} "# Version information.\ncurrent=0\nage=0\nrevision=0\n")
- file(APPEND ${_laname} "# Is this an already installed library?\ninstalled=yes\n")
- file(APPEND ${_laname} "# Should we warn about portability when linking against -modules?\nshouldnotlink=yes\n")
- file(APPEND ${_laname} "# Files to dlopen/dlpreopen\ndlopen=''\ndlpreopen=''\n")
- file(APPEND ${_laname} "# Directory that this library needs to be installed in:\n")
- file(APPEND ${_laname} "libdir='${CMAKE_INSTALL_PREFIX}/lib/kde3'\n")
-
- install_files(${KDE3_LIBTOOL_DIR} FILES ${_laname})
+ file(APPEND ${_laname} "# Version information.\ncurrent=0\nage=0\nrevision=0\n")
+ file(APPEND ${_laname} "# Is this an already installed library?\ninstalled=yes\n")
+ file(APPEND ${_laname} "# Should we warn about portability when linking against -modules?\nshouldnotlink=yes\n")
+ file(APPEND ${_laname} "# Files to dlopen/dlpreopen\ndlopen=''\ndlpreopen=''\n")
+ file(APPEND ${_laname} "# Directory that this library needs to be installed in:\n")
+ file(APPEND ${_laname} "libdir='${CMAKE_INSTALL_PREFIX}/lib/kde3'\n")
+
+ install_files(${KDE3_LIBTOOL_DIR} FILES ${_laname})
endmacro()
macro(KDE3_CREATE_FINAL_FILE _filename)
- file(WRITE ${_filename} "//autogenerated file\n")
- foreach (_current_FILE ${ARGN})
- file(APPEND ${_filename} "#include \"${_current_FILE}\"\n")
- endforeach ()
+ file(WRITE ${_filename} "//autogenerated file\n")
+ foreach (_current_FILE ${ARGN})
+ file(APPEND ${_filename} "#include \"${_current_FILE}\"\n")
+ endforeach ()
endmacro()
@@ -346,24 +347,24 @@ option(KDE3_BUILD_TESTS "Build the tests")
macro(KDE3_ADD_KPART _target_NAME _with_PREFIX)
#is the first argument is "WITH_PREFIX" then keep the standard "lib" prefix, otherwise SET the prefix empty
- if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
- set(_first_SRC)
- else ()
- set(_first_SRC ${_with_PREFIX})
- endif ()
+ if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
+ set(_first_SRC)
+ else ()
+ set(_first_SRC ${_with_PREFIX})
+ endif ()
# if (KDE3_ENABLE_FINAL)
# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${_first_SRC} ${ARGN})
# add_library(${_target_NAME} MODULE ${_target_NAME}_final.cpp)
# else ()
- add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
+ add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
# endif ()
- if(_first_SRC)
- set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
- endif()
+ if(_first_SRC)
+ set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
+ endif()
- KDE3_INSTALL_LIBTOOL_FILE(${_target_NAME})
+ KDE3_INSTALL_LIBTOOL_FILE(${_target_NAME})
endmacro()
@@ -374,13 +375,13 @@ macro(KDE3_ADD_KDEINIT_EXECUTABLE _target_NAME )
# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${ARGN})
# add_library(kdeinit_${_target_NAME} SHARED ${_target_NAME}_final.cpp)
# else ()
- add_library(kdeinit_${_target_NAME} SHARED ${ARGN} )
+ add_library(kdeinit_${_target_NAME} SHARED ${ARGN} )
# endif ()
- configure_file(${KDE3_MODULE_DIR}/kde3init_dummy.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp)
+ configure_file(${KDE3_MODULE_DIR}/kde3init_dummy.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp)
- add_executable( ${_target_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp )
- target_link_libraries( ${_target_NAME} kdeinit_${_target_NAME} )
+ add_executable( ${_target_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp )
+ target_link_libraries( ${_target_NAME} kdeinit_${_target_NAME} )
endmacro()
@@ -391,7 +392,7 @@ macro(KDE3_ADD_EXECUTABLE _target_NAME )
# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${ARGN})
# add_executable(${_target_NAME} ${_target_NAME}_final.cpp)
# else ()
- add_executable(${_target_NAME} ${ARGN} )
+ add_executable(${_target_NAME} ${ARGN} )
# endif ()
endmacro()
diff --git a/Modules/MacroAddFileDependencies.cmake b/Modules/MacroAddFileDependencies.cmake
index 39393d6cc..ca60b5702 100644
--- a/Modules/MacroAddFileDependencies.cmake
+++ b/Modules/MacroAddFileDependencies.cmake
@@ -18,13 +18,13 @@ 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}")
+ 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}")
endmacro ()
diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake
index b3078fffb..06a806b95 100644
--- a/Modules/Platform/AIX-XL.cmake
+++ b/Modules/Platform/AIX-XL.cmake
@@ -25,4 +25,26 @@ macro(__aix_compiler_xl lang)
set(CMAKE_SHARED_MODULE_${lang}_FLAGS " ")
set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+
+ # Find the CreateExportList program that comes with this toolchain.
+ find_program(CMAKE_XL_CreateExportList
+ NAMES CreateExportList
+ DOC "IBM XL CreateExportList tool"
+ )
+
+ # CMAKE_XL_CreateExportList is part of the AIX XL compilers but not the linux ones.
+ # If we found the tool, we'll use it to create exports, otherwise stick with the regular
+ # create shared library compile line.
+ if (CMAKE_XL_CreateExportList)
+ # The compiler front-end passes all object files, archive files, and shared
+ # library files named on the command line to CreateExportList to create a
+ # list of all symbols to be exported from the shared library. This causes
+ # all archive members to be copied into the shared library whether they are
+ # needed or not. Instead we run the tool ourselves to pass only the object
+ # files so that we export only the symbols actually provided by the sources.
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "${CMAKE_XL_CreateExportList} <OBJECT_DIR>/objects.exp <OBJECTS>"
+ "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+ )
+ endif()
endmacro()
diff --git a/Modules/Platform/AIX-XLClang-C.cmake b/Modules/Platform/AIX-XLClang-C.cmake
new file mode 100644
index 000000000..f0bedc5d8
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(C)
diff --git a/Modules/Platform/AIX-XLClang-CXX.cmake b/Modules/Platform/AIX-XLClang-CXX.cmake
new file mode 100644
index 000000000..cceb5769c
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(CXX)
diff --git a/Modules/Platform/AIX-XLClang.cmake b/Modules/Platform/AIX-XLClang.cmake
new file mode 100644
index 000000000..c9320950e
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang.cmake
@@ -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(__AIX_COMPILER_XLCLANG)
+ return()
+endif()
+set(__AIX_COMPILER_XLCLANG 1)
+
+include(Platform/AIX-XL)
+
+macro(__aix_compiler_xlclang lang)
+ __aix_compiler_xl(${lang})
+endmacro()
diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake
index 3d69733bb..f08f84176 100644
--- a/Modules/Platform/Android.cmake
+++ b/Modules/Platform/Android.cmake
@@ -2,9 +2,11 @@ include(Platform/Linux)
set(ANDROID 1)
-# Android has soname, but binary names must end in ".so" so we cannot append
-# a version number. Also we cannot portably represent symlinks on the host.
-set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
+# Conventionally Android does not use versioned soname
+# But in modern versions it is acceptable
+if(NOT DEFINED CMAKE_PLATFORM_NO_VERSIONED_SONAME)
+ set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
+endif()
# Android reportedly ignores RPATH, and we cannot predict the install
# location anyway.
diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake
index a1a3d3f10..f2aaf3f71 100644
--- a/Modules/Platform/CrayLinuxEnvironment.cmake
+++ b/Modules/Platform/CrayLinuxEnvironment.cmake
@@ -1,6 +1,5 @@
-# Compute Node Linux doesn't quite work the same as native Linux so all of this
-# needs to be custom. We use the variables defined through Cray's environment
-# modules to set up the right paths for things.
+# CrayLinuxEnvironment: loaded by users cross-compiling on a Cray front-end
+# node by specifying "-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment" to cmake
set(UNIX 1)
@@ -30,13 +29,6 @@ endif()
# Note: this may need to change in the future with 64-bit ARM
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
-set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
-set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
-set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
-set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
-
-set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
-
# Don't override shared lib support if it's already been set and possibly
# overridden elsewhere by the CrayPrgEnv module
if(NOT CMAKE_FIND_LIBRARY_SUFFIXES)
@@ -44,12 +36,9 @@ if(NOT CMAKE_FIND_LIBRARY_SUFFIXES)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
endif()
-set(CMAKE_DL_LIBS dl)
+# The rest of this file is based on UnixPaths.cmake, adjusted for Cray
-# Note: Much of this is pulled from UnixPaths.cmake but adjusted to the Cray
-# environment accordingly
-
-# Get the install directory of the running cmake to the search directories
+# add the install directory of the running cmake to the search directories
# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up
get_filename_component(__cmake_install_dir "${CMAKE_ROOT}" PATH)
get_filename_component(__cmake_install_dir "${__cmake_install_dir}" PATH)
@@ -81,7 +70,6 @@ if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
endif()
list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
- $ENV{SYSROOT_DIR}/usr/include
$ENV{SYSROOT_DIR}/usr/include/X11
)
list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
@@ -95,57 +83,5 @@ list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
$ENV{SYSROOT_DIR}/lib64
)
-# Compute the intersection of several lists
-function(__cray_list_intersect OUTPUT INPUT0)
- if(ARGC EQUAL 2)
- list(APPEND ${OUTPUT} ${${INPUT0}})
- else()
- foreach(I IN LISTS ${INPUT0})
- set(__is_common 1)
- foreach(L IN LISTS ARGN)
- list(FIND ${L} "${I}" __idx)
- if(__idx EQUAL -1)
- set(__is_common 0)
- break()
- endif()
- endforeach()
- if(__is_common)
- list(APPEND ${OUTPUT} "${I}")
- endif()
- endforeach()
- endif()
- set(${OUTPUT} ${${OUTPUT}} PARENT_SCOPE)
-endfunction()
-
-macro(__list_clean_dupes var)
- if(${var})
- list(REMOVE_DUPLICATES ${var})
- endif()
-endmacro()
-
-get_property(__langs GLOBAL PROPERTY ENABLED_LANGUAGES)
-set(__cray_inc_path_vars)
-set(__cray_lib_path_vars)
-foreach(__lang IN LISTS __langs)
- list(APPEND __cray_inc_path_vars CMAKE_${__lang}_IMPLICIT_INCLUDE_DIRECTORIES)
- list(APPEND __cray_lib_path_vars CMAKE_${__lang}_IMPLICIT_LINK_DIRECTORIES)
-endforeach()
-if(__cray_inc_path_vars)
- __cray_list_intersect(__cray_implicit_include_dirs ${__cray_inc_path_vars})
- if(__cray_implicit_include_dirs)
- list(INSERT CMAKE_SYSTEM_INCLUDE_PATH 0 ${__cray_implicit_include_dirs})
- endif()
-endif()
-if(__cray_lib_path_vars)
- __cray_list_intersect(__cray_implicit_library_dirs ${__cray_lib_path_vars})
- if(__cray_implicit_library_dirs)
- list(INSERT CMAKE_SYSTEM_LIBRARY_PATH 0 ${__cray_implicit_library_dirs})
- endif()
-endif()
-__list_clean_dupes(CMAKE_SYSTEM_PREFIX_PATH)
-__list_clean_dupes(CMAKE_SYSTEM_INCLUDE_PATH)
-__list_clean_dupes(CMAKE_SYSTEM_LIBRARY_PATH)
-__list_clean_dupes(CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES)
-
# Enable use of lib64 search path variants by default.
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 5590433a3..7e02814cd 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -1,11 +1,20 @@
set(APPLE 1)
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS")
- set(CMAKE_MACOSX_BUNDLE ON)
+ if(NOT DEFINED CMAKE_MACOSX_BUNDLE)
+ set(CMAKE_MACOSX_BUNDLE ON)
+ endif()
- set(CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}")
- set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
- set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+ list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}")
+ 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()
endif()
# Darwin versions:
diff --git a/Modules/Platform/GHS-MULTI-Initialize.cmake b/Modules/Platform/GHS-MULTI-Determine.cmake
index 25004c60b..349d90657 100644
--- a/Modules/Platform/GHS-MULTI-Initialize.cmake
+++ b/Modules/Platform/GHS-MULTI-Determine.cmake
@@ -3,45 +3,50 @@
#Setup Green Hills MULTI specific compilation information
-set(GHS_OS_ROOT "C:/ghs" CACHE PATH "GHS platform OS search root directory")
+if(CMAKE_HOST_UNIX)
+ set(GHS_OS_ROOT "/usr/ghs" CACHE PATH "GHS platform OS search root directory")
+else()
+ set(GHS_OS_ROOT "C:/ghs" CACHE PATH "GHS platform OS search root directory")
+endif()
mark_as_advanced(GHS_OS_ROOT)
set(GHS_OS_DIR "NOTFOUND" CACHE PATH "GHS platform OS directory")
mark_as_advanced(GHS_OS_DIR)
-set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler os option")
-mark_as_advanced(GHS_OS_DIR)
+set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler OS option")
+mark_as_advanced(GHS_OS_DIR_OPTION)
#set GHS_OS_DIR if not set by user
-if ( NOT GHS_OS_DIR )
- if (EXISTS ${GHS_OS_ROOT})
+if(NOT GHS_OS_DIR)
+ if(EXISTS ${GHS_OS_ROOT})
#get all directories in root directory
FILE(GLOB GHS_CANDIDATE_OS_DIRS
LIST_DIRECTORIES true RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
FILE(GLOB GHS_CANDIDATE_OS_FILES
LIST_DIRECTORIES false RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
- if ( GHS_CANDIDATE_OS_FILES )
+ if(GHS_CANDIDATE_OS_FILES)
list(REMOVE_ITEM GHS_CANDIDATE_OS_DIRS ${GHS_CANDIDATE_OS_FILES})
endif ()
#filter based on platform name
- if (GHS_TARGET_PLATFORM MATCHES "integrity")
- list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z].*")
+ if(GHS_TARGET_PLATFORM MATCHES "integrity")
+ list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z]")
else() #fall-back for standalone
unset(GHS_CANDIDATE_OS_DIRS)
set(GHS_OS_DIR "IGNORE")
- endif ()
+ endif()
- if (GHS_CANDIDATE_OS_DIRS)
+ if(GHS_CANDIDATE_OS_DIRS)
list(SORT GHS_CANDIDATE_OS_DIRS)
list(GET GHS_CANDIDATE_OS_DIRS -1 GHS_OS_DIR)
string(CONCAT GHS_OS_DIR ${GHS_OS_ROOT} "/" ${GHS_OS_DIR})
endif()
+ #update cache with new value
set(GHS_OS_DIR "${GHS_OS_DIR}" CACHE PATH "GHS platform OS directory" FORCE)
- endif ()
-endif ()
+ endif()
+endif()
set(GHS_BSP_NAME "IGNORE" CACHE STRING "BSP name")
diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake
index e19e89a27..78eccf706 100644
--- a/Modules/Platform/SunOS.cmake
+++ b/Modules/Platform/SunOS.cmake
@@ -1,10 +1,10 @@
if(CMAKE_SYSTEM MATCHES "SunOS-4")
- set(CMAKE_C_COMPILE_OPTIONS_PIC "-PIC")
- set(CMAKE_C_COMPILE_OPTIONS_PIE "-PIE")
- set(CMAKE_SHARED_LIBRARY_C_FLAGS "-PIC")
- set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-r")
- set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-R")
- set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+ set(CMAKE_C_COMPILE_OPTIONS_PIC "-PIC")
+ set(CMAKE_C_COMPILE_OPTIONS_PIE "-PIE")
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-PIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-r")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-R")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
endif()
include(Platform/UnixPaths)
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 007ae530d..b317da650 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -8,13 +8,120 @@ if(__WINDOWS_CLANG)
endif()
set(__WINDOWS_CLANG 1)
+macro(__windows_compiler_clang_gnu lang)
+ set(CMAKE_LIBRARY_PATH_FLAG "-L")
+ set(CMAKE_LINK_LIBRARY_FLAG "-l")
+
+ set(CMAKE_IMPORT_LIBRARY_PREFIX "")
+ set(CMAKE_SHARED_LIBRARY_PREFIX "")
+ set(CMAKE_SHARED_MODULE_PREFIX "")
+ set(CMAKE_STATIC_LIBRARY_PREFIX "")
+ set(CMAKE_EXECUTABLE_SUFFIX ".exe")
+ set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib")
+ set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+ set(CMAKE_SHARED_MODULE_SUFFIX ".dll")
+ set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
+
+ set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll" ".dll.a" ".a" ".lib")
+ set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
+ set (CMAKE_LINK_DEF_FILE_FLAG "-Xlinker /DEF:")
+
+ if("${CMAKE_${lang}_SIMULATE_VERSION}" MATCHES "^([0-9]+)\\.([0-9]+)")
+ math(EXPR MSVC_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
+ endif()
+
+ # No -fPIC on Windows
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE "")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "")
+
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+
+ # Create archiving rules to support large object file lists for static libraries.
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "<CMAKE_${lang}_COMPILER> -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -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_${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)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -D_DEBUG -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmtd)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd)
+
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(__ADDED_FLAGS "")
+ set(__ADDED_FLAGS_DEBUG "")
+ else()
+ set(__ADDED_FLAGS_DEBUG "-D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
+ set(__ADDED_FLAGS "-D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
+ endif()
+
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0 ${__ADDED_FLAGS_DEBUG}")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG ${__ADDED_FLAGS}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG ${__ADDED_FLAGS}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+
+ unset(__ADDED_FLAGS)
+ unset(__ADDED_FLAGS_DEBUG)
+ string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER)
+ set(CMAKE_${lang}_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames")
+
+ enable_language(RC)
+endmacro()
+
if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC"
OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
- include(Platform/Windows-MSVC)
- macro(__windows_compiler_clang lang)
- set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
- __windows_compiler_msvc(${lang})
- endmacro()
+
+ if ( DEFINED CMAKE_C_COMPILER_ID AND DEFINED CMAKE_CXX_COMPILER_ID
+ AND NOT "x${CMAKE_C_COMPILER_ID}" STREQUAL "x${CMAKE_CXX_COMPILER_ID}")
+ message(FATAL_ERROR "The current configuration mixes Clang and MSVC or "
+ "some other CL compatible compiler tool. This is not supported. "
+ "Use either clang or MSVC as both C and C++ compilers.")
+ endif()
+
+ if ( DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT AND DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT
+ AND NOT "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}")
+ message(FATAL_ERROR "The current configuration uses the Clang compiler "
+ "tool with mixed frontend variants, both the GNU and in MSVC CL "
+ "like variants. This is not supported. Use either clang/clang++ "
+ "or clang-cl as both C and C++ compilers.")
+ endif()
+
+ if ( "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" )
+ include(Platform/Windows-MSVC)
+
+ macro(__windows_compiler_clang lang)
+ set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
+ __windows_compiler_msvc(${lang})
+ endmacro()
+ else()
+ cmake_policy(GET CMP0091 __WINDOWS_CLANG_CMP0091)
+ if(__WINDOWS_CLANG_CMP0091 STREQUAL "NEW")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+ else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "")
+ endif()
+ unset(__WINDOWS_CLANG_CMP0091)
+
+ set(CMAKE_BUILD_TYPE_INIT Debug)
+
+ macro(__windows_compiler_clang lang)
+ __windows_compiler_clang_gnu(${lang})
+ endmacro()
+ endif()
+
else()
include(Platform/Windows-GNU)
macro(__windows_compiler_clang lang)
diff --git a/Modules/Platform/Windows-Intel-Fortran.cmake b/Modules/Platform/Windows-Intel-Fortran.cmake
index 3981a092b..e3804fb86 100644
--- a/Modules/Platform/Windows-Intel-Fortran.cmake
+++ b/Modules/Platform/Windows-Intel-Fortran.cmake
@@ -4,8 +4,41 @@ set(_COMPILE_Fortran " /fpp")
set(CMAKE_Fortran_MODDIR_FLAG "-module:")
set(CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
__windows_compiler_intel(Fortran)
-string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1 /nologo /fpp /libs:dll /threads")
-string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full /dbglibs")
+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-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index a6448a0ff..7a83859ec 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -17,7 +17,7 @@ set(MSVC 1)
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
# hardcode CMAKE_LINKER here to link, so it behaves as it did before, Alex
if(NOT DEFINED CMAKE_LINKER)
- set(CMAKE_LINKER link)
+ set(CMAKE_LINKER link)
endif()
if(CMAKE_VERBOSE_MAKEFILE)
@@ -298,6 +298,14 @@ endforeach()
string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
unset(_MACHINE_ARCH_FLAG)
+cmake_policy(GET CMP0091 __WINDOWS_MSVC_CMP0091)
+if(__WINDOWS_MSVC_CMP0091 STREQUAL "NEW")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "")
+endif()
+unset(__WINDOWS_MSVC_CMP0091)
+
macro(__windows_compiler_msvc lang)
if(NOT MSVC_VERSION LESS 1400)
# for 2005 make sure the manifest is put in the dll with mt
@@ -351,21 +359,48 @@ macro(__windows_compiler_msvc lang)
if("x${lang}" STREQUAL "xC" OR
"x${lang}" STREQUAL "xCXX")
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_MDd "")
+ set(_MD "")
+ else()
+ set(_MDd " /MDd")
+ set(_MD " /MD")
+ endif()
+
+ cmake_policy(GET CMP0092 _cmp0092)
+ if(_cmp0092 STREQUAL "NEW")
+ set(_W3 "")
+ set(_Wall "")
+ else()
+ set(_W3 " /W3")
+ set(_Wall " -Wall")
+ endif()
+ unset(_cmp0092)
+
if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
# note: MSVC 14 2015 Update 1 sets -fno-ms-compatibility by default, but this does not allow one to compile many projects
# that include MS's own headers. CMake itself is affected project too.
- string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS -Wall${_FLAGS_${lang}}")
- string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " /MDd -gline-tables-only -fno-inline -O0 ${_RTC1}")
- string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " /MD -O2 -DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " /MD -gline-tables-only -O2 -fno-inline -DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " /MD -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS${_Wall}${_FLAGS_${lang}}")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} -gline-tables-only -fno-inline -O0 ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} -O2 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} -gline-tables-only -O2 -fno-inline -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
else()
- string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS /W3${_FLAGS_${lang}}")
- string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " /MDd /Zi /Ob0 /Od ${_RTC1}")
- string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " /MD /O2 /Ob2 /DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " /MD /Zi /O2 /Ob1 /DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " /MD /O1 /Ob1 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS${_W3}${_FLAGS_${lang}}")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} /Zi /Ob0 /Od ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} /Zi /O2 /Ob1 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
endif()
+ unset(_Wall)
+ unset(_W3)
+ unset(_MDd)
+ unset(_MD)
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -MT)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -MD)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -MTd)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd)
endif()
set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
set(CMAKE_NINJA_DEPTYPE_${lang} msvc)
@@ -377,12 +412,16 @@ macro(__windows_compiler_msvc_enable_rc flags)
set(CMAKE_RC_COMPILER_INIT rc)
endif()
if(NOT CMAKE_RC_FLAGS_INIT)
- string(APPEND CMAKE_RC_FLAGS_INIT " ${flags}")
+ # llvm-rc fails when flags are specified with /D and no space after
+ string(REPLACE " /D" " -D" fixed_flags " ${flags}")
+ string(APPEND CMAKE_RC_FLAGS_INIT " ${fixed_flags}")
endif()
if(NOT CMAKE_RC_FLAGS_DEBUG_INIT)
- string(APPEND CMAKE_RC_FLAGS_DEBUG_INIT " /D_DEBUG")
+ string(APPEND CMAKE_RC_FLAGS_DEBUG_INIT " -D_DEBUG")
endif()
enable_language(RC)
- set(CMAKE_NINJA_CMCLDEPS_RC 1)
+ if(NOT DEFINED CMAKE_NINJA_CMCLDEPS_RC)
+ set(CMAKE_NINJA_CMCLDEPS_RC 1)
+ endif()
endmacro()
diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
index 6a2667aa6..94d77b961 100644
--- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
@@ -60,11 +60,35 @@ unset(__IMPLICT_DLINK_FLAGS)
string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")
-string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"/W3${_FLAGS_CXX}\"")
-string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"-MDd -Zi -Ob0 -Od ${_RTC1}\"")
-string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"-MD -O2 -Ob2\" -DNDEBUG")
-string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"-MD -Zi -O2 -Ob1\" -DNDEBUG")
-string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"-MD -O1 -Ob1\" -DNDEBUG")
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_MDd "")
+ set(_MD "")
+else()
+ set(_MDd "-MDd ")
+ set(_MD "-MD ")
+endif()
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(_cmp0092 STREQUAL "NEW")
+ set(_W3 "")
+else()
+ set(_W3 "/W3")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
+string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}-Zi -Ob0 -Od ${_RTC1}\"")
+string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG")
+string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"${_MD}-Zi -O2 -Ob1\" -DNDEBUG")
+string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"${_MD}-O1 -Ob1\" -DNDEBUG")
+unset(_W3)
+unset(_MDd)
+unset(_MD)
+
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xcompiler=-MT)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -Xcompiler=-MD)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -Xcompiler=-MTd)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -Xcompiler=-MDd)
set(CMAKE_CUDA_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
diff --git a/Modules/ProcessorCount.cmake b/Modules/ProcessorCount.cmake
index e4b4e5372..8c252566a 100644
--- a/Modules/ProcessorCount.cmake
+++ b/Modules/ProcessorCount.cmake
@@ -70,6 +70,20 @@ function(ProcessorCount var)
endif()
if(NOT count)
+ # Linux (systems with nproc):
+ # Prefer nproc to getconf if available as getconf may return the host CPU count in Linux containers
+ find_program(ProcessorCount_cmd_nproc nproc)
+ mark_as_advanced(ProcessorCount_cmd_nproc)
+ if(ProcessorCount_cmd_nproc)
+ execute_process(COMMAND ${ProcessorCount_cmd_nproc}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE count)
+ #message("ProcessorCount: trying nproc '${ProcessorCount_cmd_nproc}'")
+ endif()
+ endif()
+
+ if(NOT count)
# Linux (systems with getconf):
find_program(ProcessorCount_cmd_getconf getconf)
mark_as_advanced(ProcessorCount_cmd_getconf)
diff --git a/Modules/Qt4Macros.cmake b/Modules/Qt4Macros.cmake
index 5c489709d..33cacf10b 100644
--- a/Modules/Qt4Macros.cmake
+++ b/Modules/Qt4Macros.cmake
@@ -140,20 +140,20 @@ endfunction ()
macro (QT4_GENERATE_MOC infile outfile )
-# get include dirs and flags
- QT4_GET_MOC_FLAGS(moc_flags)
- get_filename_component(abs_infile ${infile} ABSOLUTE)
- set(_outfile "${outfile}")
- if(NOT IS_ABSOLUTE "${outfile}")
- set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
- endif()
-
- if (${ARGC} GREATER 3 AND "x${ARGV2}" STREQUAL "xTARGET")
- set(moc_target ${ARGV3})
- endif()
- QT4_CREATE_MOC_COMMAND(${abs_infile} ${_outfile} "${moc_flags}" "" "${moc_target}")
- set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
- set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+ # get include dirs and flags
+ QT4_GET_MOC_FLAGS(moc_flags)
+ get_filename_component(abs_infile ${infile} ABSOLUTE)
+ set(_outfile "${outfile}")
+ if(NOT IS_ABSOLUTE "${outfile}")
+ set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
+ endif()
+
+ if (${ARGC} GREATER 3 AND "x${ARGV2}" STREQUAL "xTARGET")
+ set(moc_target ${ARGV3})
+ endif()
+ QT4_CREATE_MOC_COMMAND(${abs_infile} ${_outfile} "${moc_flags}" "" "${moc_target}")
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
endmacro ()
@@ -414,49 +414,49 @@ endmacro()
macro(QT4_CREATE_TRANSLATION _qm_files)
- QT4_EXTRACT_OPTIONS(_lupdate_files _lupdate_options _lupdate_target ${ARGN})
- set(_my_sources)
- set(_my_dirs)
- set(_my_tsfiles)
- set(_ts_pro)
- foreach (_file ${_lupdate_files})
- get_filename_component(_ext ${_file} EXT)
- get_filename_component(_abs_FILE ${_file} ABSOLUTE)
- if(_ext MATCHES "ts")
- list(APPEND _my_tsfiles ${_abs_FILE})
- else()
- if(NOT _ext)
- list(APPEND _my_dirs ${_abs_FILE})
- else()
- list(APPEND _my_sources ${_abs_FILE})
- endif()
- endif()
- endforeach()
- foreach(_ts_file ${_my_tsfiles})
- if(_my_sources)
- # make a .pro file to call lupdate on, so we don't make our commands too
- # long for some systems
- get_filename_component(_ts_name ${_ts_file} NAME_WE)
- set(_ts_pro ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lupdate.pro)
- set(_pro_srcs)
- foreach(_pro_src ${_my_sources})
- string(APPEND _pro_srcs " \\\n \"${_pro_src}\"")
- endforeach()
- set(_pro_includes)
- get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
- list(REMOVE_DUPLICATES _inc_DIRS)
- foreach(_pro_include ${_inc_DIRS})
- get_filename_component(_abs_include "${_pro_include}" ABSOLUTE)
- string(APPEND _pro_includes " \\\n \"${_abs_include}\"")
- endforeach()
- file(GENERATE OUTPUT ${_ts_pro} CONTENT "SOURCES =${_pro_srcs}\nINCLUDEPATH =${_pro_includes}\n")
- endif()
- add_custom_command(OUTPUT ${_ts_file}
+ QT4_EXTRACT_OPTIONS(_lupdate_files _lupdate_options _lupdate_target ${ARGN})
+ set(_my_sources)
+ set(_my_dirs)
+ set(_my_tsfiles)
+ set(_ts_pro)
+ foreach (_file ${_lupdate_files})
+ get_filename_component(_ext ${_file} EXT)
+ get_filename_component(_abs_FILE ${_file} ABSOLUTE)
+ if(_ext MATCHES "ts")
+ list(APPEND _my_tsfiles ${_abs_FILE})
+ else()
+ if(NOT _ext)
+ list(APPEND _my_dirs ${_abs_FILE})
+ else()
+ list(APPEND _my_sources ${_abs_FILE})
+ endif()
+ endif()
+ endforeach()
+ foreach(_ts_file ${_my_tsfiles})
+ if(_my_sources)
+ # make a .pro file to call lupdate on, so we don't make our commands too
+ # long for some systems
+ get_filename_component(_ts_name ${_ts_file} NAME_WE)
+ set(_ts_pro ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lupdate.pro)
+ set(_pro_srcs)
+ foreach(_pro_src ${_my_sources})
+ string(APPEND _pro_srcs " \\\n \"${_pro_src}\"")
+ endforeach()
+ set(_pro_includes)
+ get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
+ list(REMOVE_DUPLICATES _inc_DIRS)
+ foreach(_pro_include ${_inc_DIRS})
+ get_filename_component(_abs_include "${_pro_include}" ABSOLUTE)
+ string(APPEND _pro_includes " \\\n \"${_abs_include}\"")
+ endforeach()
+ file(GENERATE OUTPUT ${_ts_pro} CONTENT "SOURCES =${_pro_srcs}\nINCLUDEPATH =${_pro_includes}\n")
+ endif()
+ add_custom_command(OUTPUT ${_ts_file}
COMMAND Qt4::lupdate
ARGS ${_lupdate_options} ${_ts_pro} ${_my_dirs} -ts ${_ts_file}
DEPENDS ${_my_sources} ${_ts_pro} VERBATIM)
- endforeach()
- QT4_ADD_TRANSLATION(${_qm_files} ${_my_tsfiles})
+ endforeach()
+ QT4_ADD_TRANSLATION(${_qm_files} ${_my_tsfiles})
endmacro()
diff --git a/Modules/UseEcos.cmake b/Modules/UseEcos.cmake
index 9f848475b..60324b1bd 100644
--- a/Modules/UseEcos.cmake
+++ b/Modules/UseEcos.cmake
@@ -32,38 +32,38 @@ internal use only:
# first check that ecosconfig is available
find_program(ECOSCONFIG_EXECUTABLE NAMES ecosconfig)
if(NOT ECOSCONFIG_EXECUTABLE)
- message(SEND_ERROR "ecosconfig was not found. Either include it in the system path or set it manually using ccmake.")
+ message(SEND_ERROR "ecosconfig was not found. Either include it in the system path or set it manually using ccmake.")
else()
- message(STATUS "Found ecosconfig: ${ECOSCONFIG_EXECUTABLE}")
+ message(STATUS "Found ecosconfig: ${ECOSCONFIG_EXECUTABLE}")
endif()
# check that ECOS_REPOSITORY is set correctly
if (NOT EXISTS $ENV{ECOS_REPOSITORY}/ecos.db)
- message(SEND_ERROR "The environment variable ECOS_REPOSITORY is not set correctly. Set it to the directory which contains the file ecos.db")
+ message(SEND_ERROR "The environment variable ECOS_REPOSITORY is not set correctly. Set it to the directory which contains the file ecos.db")
else ()
- message(STATUS "ECOS_REPOSITORY is set to $ENV{ECOS_REPOSITORY}")
+ message(STATUS "ECOS_REPOSITORY is set to $ENV{ECOS_REPOSITORY}")
endif ()
# check that tclsh (coming with TCL) is available, otherwise ecosconfig doesn't work
find_package(Tclsh)
if (NOT TCL_TCLSH)
- message(SEND_ERROR "The TCL tclsh was not found. Please install TCL, it is required for building eCos applications.")
+ message(SEND_ERROR "The TCL tclsh was not found. Please install TCL, it is required for building eCos applications.")
else ()
- message(STATUS "tlcsh found: ${TCL_TCLSH}")
+ message(STATUS "tlcsh found: ${TCL_TCLSH}")
endif ()
#add the globale include-diretories
#usage: ECOS_ADD_INCLUDE_DIRECTORIES()
macro(ECOS_ADD_INCLUDE_DIRECTORIES)
#check for ProjectSources.txt one level higher
- if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../ProjectSources.txt)
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
- else ()
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/)
- endif ()
+ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../ProjectSources.txt)
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+ else ()
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/)
+ endif ()
#the ecos include directory
- include_directories(${CMAKE_CURRENT_BINARY_DIR}/ecos/install/include/)
+ include_directories(${CMAKE_CURRENT_BINARY_DIR}/ecos/install/include/)
endmacro()
@@ -71,47 +71,47 @@ endmacro()
#we want to compile for the xscale processor, in this case the following macro has to be called
#usage: ECOS_USE_ARM_ELF_TOOLS()
macro (ECOS_USE_ARM_ELF_TOOLS)
- set(CMAKE_CXX_COMPILER "arm-elf-c++")
- set(CMAKE_COMPILER_IS_GNUCXX 1)
- set(CMAKE_C_COMPILER "arm-elf-gcc")
- set(CMAKE_AR "arm-elf-ar")
- set(CMAKE_RANLIB "arm-elf-ranlib")
+ set(CMAKE_CXX_COMPILER "arm-elf-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "arm-elf-gcc")
+ set(CMAKE_AR "arm-elf-ar")
+ set(CMAKE_RANLIB "arm-elf-ranlib")
#for linking
- set(ECOS_LD_MCPU "-mcpu=xscale")
+ set(ECOS_LD_MCPU "-mcpu=xscale")
#for compiling
- add_definitions(-mcpu=xscale -mapcs-frame)
+ add_definitions(-mcpu=xscale -mapcs-frame)
#for the obj-tools
- set(ECOS_ARCH_PREFIX "arm-elf-")
+ set(ECOS_ARCH_PREFIX "arm-elf-")
endmacro ()
#usage: ECOS_USE_PPC_EABI_TOOLS()
macro (ECOS_USE_PPC_EABI_TOOLS)
- set(CMAKE_CXX_COMPILER "powerpc-eabi-c++")
- set(CMAKE_COMPILER_IS_GNUCXX 1)
- set(CMAKE_C_COMPILER "powerpc-eabi-gcc")
- set(CMAKE_AR "powerpc-eabi-ar")
- set(CMAKE_RANLIB "powerpc-eabi-ranlib")
+ set(CMAKE_CXX_COMPILER "powerpc-eabi-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "powerpc-eabi-gcc")
+ set(CMAKE_AR "powerpc-eabi-ar")
+ set(CMAKE_RANLIB "powerpc-eabi-ranlib")
#for linking
- set(ECOS_LD_MCPU "")
+ set(ECOS_LD_MCPU "")
#for compiling
- add_definitions()
+ add_definitions()
#for the obj-tools
- set(ECOS_ARCH_PREFIX "powerpc-eabi-")
+ set(ECOS_ARCH_PREFIX "powerpc-eabi-")
endmacro ()
#usage: ECOS_USE_I386_ELF_TOOLS()
macro (ECOS_USE_I386_ELF_TOOLS)
- set(CMAKE_CXX_COMPILER "i386-elf-c++")
- set(CMAKE_COMPILER_IS_GNUCXX 1)
- set(CMAKE_C_COMPILER "i386-elf-gcc")
- set(CMAKE_AR "i386-elf-ar")
- set(CMAKE_RANLIB "i386-elf-ranlib")
+ set(CMAKE_CXX_COMPILER "i386-elf-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "i386-elf-gcc")
+ set(CMAKE_AR "i386-elf-ar")
+ set(CMAKE_RANLIB "i386-elf-ranlib")
#for linking
- set(ECOS_LD_MCPU "")
+ set(ECOS_LD_MCPU "")
#for compiling
- add_definitions()
+ add_definitions()
#for the obj-tools
- set(ECOS_ARCH_PREFIX "i386-elf-")
+ set(ECOS_ARCH_PREFIX "i386-elf-")
endmacro ()
@@ -122,13 +122,13 @@ endmacro ()
#followed by all source files
#usage: ECOS_ADJUST_DIRECTORY(adjusted_SRCS ${my_srcs})
macro(ECOS_ADJUST_DIRECTORY _target_FILES )
- foreach (_current_FILE ${ARGN})
- get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+ foreach (_current_FILE ${ARGN})
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
if (NOT ${_abs_FILE} STREQUAL ${_current_FILE})
- get_filename_component(_abs_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../${_current_FILE} ABSOLUTE)
+ get_filename_component(_abs_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../${_current_FILE} ABSOLUTE)
endif ()
- list(APPEND ${_target_FILES} ${_abs_FILE})
- endforeach ()
+ list(APPEND ${_target_FILES} ${_abs_FILE})
+ endforeach ()
endmacro()
# the default ecos config file name
@@ -139,29 +139,29 @@ set(ECOS_CONFIG_FILE ecos.ecc)
#adds the command for compiling ecos
macro(ECOS_ADD_TARGET_LIB)
# when building out-of-source, create the ecos/ subdir
- if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/ecos)
- file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ecos)
- endif()
+ if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/ecos)
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ecos)
+ endif()
#sources depend on target.ld
- set_source_files_properties(
- ${ARGN}
- PROPERTIES
- OBJECT_DEPENDS
- ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
- )
-
- add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
- COMMAND sh -c \"make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos || exit -1\; if [ -e ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld ] \; then touch ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld\; fi\"
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
- )
-
- add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
- COMMAND sh -c \" cd ${CMAKE_CURRENT_BINARY_DIR}/ecos\; ${ECOSCONFIG_EXECUTABLE} --config=${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE} tree || exit -1\;\"
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE}
- )
-
- add_custom_target( ecos make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos/ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile )
+ set_source_files_properties(
+ ${ARGN}
+ PROPERTIES
+ OBJECT_DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
+ )
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
+ COMMAND sh -c \"make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos || exit -1\; if [ -e ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld ] \; then touch ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld\; fi\"
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
+ )
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
+ COMMAND sh -c \" cd ${CMAKE_CURRENT_BINARY_DIR}/ecos\; ${ECOSCONFIG_EXECUTABLE} --config=${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE} tree || exit -1\;\"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE}
+ )
+
+ add_custom_target( ecos make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos/ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile )
endmacro()
# get the directory of the current file, used later on in the file
@@ -173,64 +173,64 @@ get_filename_component( ECOS_CMAKE_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
#has been adjusted beforehand by calling ECOS_ADJUST_DIRECTORY()
#usage: ECOS_ADD_EXECUTABLE(my_app ${adjusted_SRCS})
macro(ECOS_ADD_EXECUTABLE _exe_NAME )
- #definitions, valid for all ecos projects
- #the optimization and "-g" for debugging has to be enabled
- #in the project-specific CMakeLists.txt
- add_definitions(-D__ECOS__=1 -D__ECOS=1)
- set(ECOS_DEFINITIONS -Wall -Wno-long-long -pipe -fno-builtin)
+ #definitions, valid for all ecos projects
+ #the optimization and "-g" for debugging has to be enabled
+ #in the project-specific CMakeLists.txt
+ add_definitions(-D__ECOS__=1 -D__ECOS=1)
+ set(ECOS_DEFINITIONS -Wall -Wno-long-long -pipe -fno-builtin)
#the executable depends on ecos target.ld
- ECOS_ADD_TARGET_LIB(${ARGN})
+ ECOS_ADD_TARGET_LIB(${ARGN})
# when using nmake makefiles, the custom buildtype suppresses the default cl.exe flags
# and the rules for creating objects are adjusted for gcc
- set(CMAKE_BUILD_TYPE CUSTOM_ECOS_BUILD)
- set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
- set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ set(CMAKE_BUILD_TYPE CUSTOM_ECOS_BUILD)
+ set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
# special link commands for ecos-executables
- set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
- set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+ set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+ set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
# some strict compiler flags
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
- set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual -fno-rtti -Wctor-dtor-privacy -fno-strict-aliasing -fno-exceptions")
+ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual -fno-rtti -Wctor-dtor-privacy -fno-strict-aliasing -fno-exceptions")
- add_executable(${_exe_NAME} ${ARGN})
- set_target_properties(${_exe_NAME} PROPERTIES SUFFIX ".elf")
+ add_executable(${_exe_NAME} ${ARGN})
+ set_target_properties(${_exe_NAME} PROPERTIES SUFFIX ".elf")
#create a binary file
- add_custom_command(
- TARGET ${_exe_NAME}
- POST_BUILD
- COMMAND ${ECOS_ARCH_PREFIX}objcopy
- ARGS -O binary ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin
- )
+ add_custom_command(
+ TARGET ${_exe_NAME}
+ POST_BUILD
+ COMMAND ${ECOS_ARCH_PREFIX}objcopy
+ ARGS -O binary ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin
+ )
#and an srec file
- add_custom_command(
- TARGET ${_exe_NAME}
- POST_BUILD
- COMMAND ${ECOS_ARCH_PREFIX}objcopy
- ARGS -O srec ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec
- )
+ add_custom_command(
+ TARGET ${_exe_NAME}
+ POST_BUILD
+ COMMAND ${ECOS_ARCH_PREFIX}objcopy
+ ARGS -O srec ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec
+ )
#add the created files to the clean-files
- set_directory_properties(
- PROPERTIES
- ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin;${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec;${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst;"
- )
-
- add_custom_target(ecosclean ${CMAKE_COMMAND} -DECOS_DIR=${CMAKE_CURRENT_BINARY_DIR}/ecos/ -P ${ECOS_CMAKE_MODULE_DIR}/ecos_clean.cmake )
- add_custom_target(normalclean ${CMAKE_MAKE_PROGRAM} clean WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- add_dependencies (ecosclean normalclean)
-
-
- add_custom_target( listing
- COMMAND echo -e \"\\n--- Symbols sorted by address ---\\n\" > ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
- COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -n ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
- COMMAND echo -e \"\\n--- Symbols sorted by size ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
- COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -r --size-sort ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
- COMMAND echo -e \"\\n--- Full assembly listing ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
- COMMAND ${ECOS_ARCH_PREFIX}objdump -S -x -d -C ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst )
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin"
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec"
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst")
+
+ add_custom_target(ecosclean ${CMAKE_COMMAND} -DECOS_DIR=${CMAKE_CURRENT_BINARY_DIR}/ecos/ -P ${ECOS_CMAKE_MODULE_DIR}/ecos_clean.cmake )
+ add_custom_target(normalclean ${CMAKE_MAKE_PROGRAM} clean WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ add_dependencies (ecosclean normalclean)
+
+
+ add_custom_target( listing
+ COMMAND echo -e \"\\n--- Symbols sorted by address ---\\n\" > ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -n ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND echo -e \"\\n--- Symbols sorted by size ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -r --size-sort ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND echo -e \"\\n--- Full assembly listing ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}objdump -S -x -d -C ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst )
endmacro()
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index 5600b4c1c..07984885b 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -8,289 +8,234 @@ UseJava
Use Module for Java
This file provides functions for Java. It is assumed that
-FindJava.cmake has already been loaded. See FindJava.cmake for
+:module:`FindJava` has already been loaded. See :module:`FindJava` for
information on how to load Java into your CMake project.
-::
+Creating And Installing JARs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_jar(<target_name>
+ [SOURCES] <source1> [<source2>...] [<resource1>...]
+ [INCLUDE_JARS <jar1> [<jar2>...]]
+ [ENTRY_POINT <entry>]
+ [VERSION <version>]
+ [OUTPUT_NAME <name>]
+ [OUTPUT_DIR <dir>]
+ [GENERATE_NATIVE_HEADERS <target> [DESTINATION <dir>]]
+ )
- add_jar(target_name
- [SOURCES] source1 [source2 ...] [resource1 ...]
- [INCLUDE_JARS jar1 [jar2 ...]]
- [ENTRY_POINT entry]
- [VERSION version]
- [OUTPUT_NAME name]
- [OUTPUT_DIR dir]
- [GENERATE_NATIVE_HEADERS target [DESTINATION dir]]
- )
-
-This command creates a <target_name>.jar. It compiles the given
-source files (source) and adds the given resource files (resource) to
+This command creates a ``<target_name>.jar``. It compiles the given
+``<source>`` files and adds the given ``<resource>`` files to
the jar file. Source files can be java files or listing files
-(prefixed by '@'). If only resource files are given then just a jar file
-is created. The list of include jars are added to the classpath when
+(prefixed by ``@``). If only resource files are given then just a jar file
+is created. The list of ``INCLUDE_JARS`` are added to the classpath when
compiling the java sources and also to the dependencies of the target.
-INCLUDE_JARS also accepts other target names created by add_jar. For
-backwards compatibility, jar files listed as sources are ignored (as
+``INCLUDE_JARS`` also accepts other target names created by ``add_jar()``.
+For backwards compatibility, jar files listed as sources are ignored (as
they have been since the first version of this module).
-The default OUTPUT_DIR can also be changed by setting the variable
-CMAKE_JAVA_TARGET_OUTPUT_DIR.
+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 output directory for
-generated header files.
+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.
-Additional instructions:
+The ``add_jar()`` function sets the following target properties on
+``<target_name>``:
-::
-
- To add compile flags to the target you can set these flags with
- the following variable:
+``INSTALL_FILES``
+ The files which should be installed. This is used by ``install_jar()``.
+``JNI_SYMLINK``
+ The JNI symlink which should be installed. This is used by
+ ``install_jni_symlink()``.
+``JAR_FILE``
+ The location of the jar file so that you can include it.
+``CLASSDIR``
+ The directory where the class files can be found. For example to use them
+ with ``javah``.
+.. code-block:: cmake
+ install_jar(<target_name> <destination>)
+ install_jar(<target_name> DESTINATION <destination> [COMPONENT <component>])
-::
-
- set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
+This command installs the ``<target_name>`` files to the given
+``<destination>``. It should be called in the same scope as ``add_jar()`` or
+it will fail.
+The ``install_jar()`` function sets the ``INSTALL_DESTINATION`` target
+property on jars so installed. This property holds the ``<destination>`` as
+described above, and is used by ``install_jar_exports()``. You can get this
+information with :command:`get_property` and the ``INSTALL_DESTINATION``
+property key.
+.. code-block:: cmake
-::
-
- To add a path or a jar file to the class path you can do this
- with the CMAKE_JAVA_INCLUDE_PATH variable.
-
-
-
-::
-
- set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
-
-
-
-::
-
- To use a different output name for the target you can set it with:
-
-
-
-::
-
- add_jar(foobar foobar.java OUTPUT_NAME shibboleet.jar)
-
-
-
-::
+ install_jni_symlink(<target_name> <destination>)
+ install_jni_symlink(<target_name> DESTINATION <destination> [COMPONENT <component>])
- To use a different output directory than CMAKE_CURRENT_BINARY_DIR
- you can set it with:
+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.
+.. code-block:: cmake
+ install_jar_exports(TARGETS <jars>...
+ [NAMESPACE <namespace>]
+ FILE <filename>
+ DESTINATION <destination> [COMPONENT <component>])
-::
-
- add_jar(foobar foobar.java OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
-
-
-
-::
-
- To define an entry point in your jar you can set it with the ENTRY_POINT
- named argument:
-
-
-
-::
-
- add_jar(example ENTRY_POINT com/examples/MyProject/Main)
-
-
-
-::
-
- To define a custom manifest for the jar, you can set it with the manifest
- named argument:
-
-
-
-::
-
- add_jar(example MANIFEST /path/to/manifest)
-
-
-
-::
-
- To add a VERSION to the target output name you can set it using
- the VERSION named argument to add_jar. This will create a jar file with the
- name shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
- pointing to the jar with the version information.
+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)`.
+.. code-block:: cmake
+ export_jars(TARGETS <jars>...
+ [NAMESPACE <namespace>]
+ FILE <filename>)
-::
+This command writes a target export file ``<filename>`` for the named ``<jars>``
+targets. Its function is similar to that of :command:`export`.
- add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
+Examples
+""""""""
+To add compile flags to the target you can set these flags with the following
+variable:
-::
+.. code-block:: cmake
- If the target is a JNI library, utilize the following commands to
- create a JNI symbolic link:
+ set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
+To add a path or a jar file to the class path you can do this with the
+``CMAKE_JAVA_INCLUDE_PATH`` variable.
-::
+.. code-block:: cmake
- set(CMAKE_JNI_TARGET TRUE)
- add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
- install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
- install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
+ set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
+To use a different output name for the target you can set it with:
+.. code-block:: cmake
-::
+ add_jar(foobar foobar.java OUTPUT_NAME shibboleet.jar)
- If a single target needs to produce more than one jar from its
- java source code, to prevent the accumulation of duplicate class
- files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
- to calling the add_jar() function:
+To use a different output directory than ``CMAKE_CURRENT_BINARY_DIR`` you can
+set it with:
+.. code-block:: cmake
+ add_jar(foobar foobar.java OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
-::
+To define an entry point in your jar you can set it with the ``ENTRY_POINT``
+named argument:
- set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
- add_jar(foo foo.java)
+.. code-block:: cmake
+ add_jar(example ENTRY_POINT com/examples/MyProject/Main)
+To define a custom manifest for the jar, you can set it with the ``MANIFEST``
+named argument:
-::
+.. code-block:: cmake
- set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
- add_jar(bar bar.java)
+ add_jar(example MANIFEST /path/to/manifest)
+To add a version to the target output name you can set it using the ``VERSION``
+named argument to ``add_jar()``. The following example will create a jar file
+with the name ``shibboleet-1.0.0.jar`` and will create a symlink
+``shibboleet.jar`` pointing to the jar with the version information.
+.. code-block:: cmake
-::
+ add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
- For an optimum usage of option GENERATE_NATIVE_HEADERS, it is recommended to
- include module JNI before any call to add_jar. The produced target for native
- headers can then be used to compile C/C++ sources with command
- target_link_libraries.
+If the target is a JNI library, utilize the following commands to
+create a JNI symbolic link:
+.. code-block:: cmake
-::
+ set(CMAKE_JNI_TARGET TRUE)
+ add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
+ install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
+ install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
- find_package(JNI)
- add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native)
- add_library(bar bar.cpp)
- target_link_libraries(bar PRIVATE foo-native)
+If a single target needs to produce more than one jar from its
+java source code, to prevent the accumulation of duplicate class
+files in subsequent jars, set/reset ``CMAKE_JAR_CLASSES_PREFIX`` prior
+to calling the ``add_jar()`` function:
+.. code-block:: cmake
-Target Properties:
+ set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
+ add_jar(foo foo.java)
-::
+ set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
+ add_jar(bar bar.java)
- The add_jar() function sets some target properties. You can get these
- properties with the
- get_property(TARGET <target_name> PROPERTY <propery_name>)
- command.
+For an optimum usage of option ``GENERATE_NATIVE_HEADERS``, it is recommended to
+include module JNI before any call to ``add_jar()``. The produced target for
+native headers can then be used to compile C/C++ sources with the
+:command:`target_link_libraries` command.
+.. code-block:: cmake
+ find_package(JNI)
+ add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native)
+ add_library(bar bar.cpp)
+ target_link_libraries(bar PRIVATE foo-native)
-::
- INSTALL_FILES The files which should be installed. This is used by
- install_jar().
- JNI_SYMLINK The JNI symlink which should be installed.
- This is used by install_jni_symlink().
- JAR_FILE The location of the jar file so that you can include
- it.
- CLASSDIR The directory where the class files can be found. For
- example to use them with javah.
+Finding JARs
+^^^^^^^^^^^^
-::
+.. code-block:: cmake
- find_jar(<VAR>
- name | NAMES name1 [name2 ...]
- [PATHS path1 [path2 ... ENV var]]
- [VERSIONS version1 [version2]]
- [DOC "cache documentation string"]
+ find_jar(<VAR>
+ <name> | NAMES <name1> [<name2>...]
+ [PATHS <path1> [<path2>... ENV <var>]]
+ [VERSIONS <version1> [<version2>]]
+ [DOC "cache documentation string"]
)
This command is used to find a full path to the named jar. A cache
-entry named by <VAR> is created to stor the result of this command.
+entry named by ``<VAR>`` is created to store the result of this command.
If the full path to a jar is found the result is stored in the
variable and the search will not repeated unless the variable is
-cleared. If nothing is found, the result will be <VAR>-NOTFOUND, and
-the search will be attempted again next time find_jar is invoked with
+cleared. If nothing is found, the result will be ``<VAR>-NOTFOUND``, and
+the search will be attempted again next time ``find_jar()`` is invoked with
the same variable. The name of the full path to a file that is
-searched for is specified by the names listed after NAMES argument.
-Additional search locations can be specified after the PATHS argument.
+searched for is specified by the names listed after ``NAMES`` argument.
+Additional search locations can be specified after the ``PATHS`` argument.
If you require special a version of a jar file you can specify it with
-the VERSIONS argument. The argument after DOC will be used for the
+the ``VERSIONS`` argument. The argument after ``DOC`` will be used for the
documentation string in the cache.
-::
-
- install_jar(target_name destination)
- install_jar(target_name DESTINATION destination [COMPONENT component])
-
-This command installs the TARGET_NAME files to the given DESTINATION.
-It should be called in the same scope as add_jar() or it will fail.
-
-Target Properties:
-
-::
-
- The install_jar() function sets the INSTALL_DESTINATION target property
- on jars so installed. This property holds the DESTINATION as described
- above, and is used by install_jar_exports(). You can get this property
- with the
- get_property(TARGET <target_name> PROPERTY INSTALL_DESTINATION)
- command.
+Javadoc
+^^^^^^^
+The ``create_javadoc()`` command can be used to create java documentation
+based on files or packages. For more details please read the javadoc manpage.
-::
-
- install_jni_symlink(target_name destination)
- install_jni_symlink(target_name DESTINATION destination [COMPONENT component])
+There are two main signatures for ``create_javadoc()``. The first signature
+works with package names on a path with source files.
-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.
-
-::
-
- install_jar_exports(TARGETS jars...
- [NAMESPACE <namespace>]
- FILE <filename>
- DESTINATION <dir> [COMPONENT <component>])
-
-This command installs a target export file ``<filename>`` for the named jar
-targets to the given ``DESTINATION``. Its function is similar to that of
-:command:`install(EXPORTS ...)`.
-
-::
-
- export_jars(TARGETS jars...
- [NAMESPACE <namespace>]
- FILE <filename>)
-
-This command writes a target export file ``<filename>`` for the named jar
-targets. Its function is similar to that of :command:`export(...)`.
-
-::
+.. code-block:: cmake
create_javadoc(<VAR>
- PACKAGES pkg1 [pkg2 ...]
+ PACKAGES <pkg1> [<pkg2>...]
[SOURCEPATH <sourcepath>]
[CLASSPATH <classpath>]
[INSTALLPATH <install path>]
@@ -301,80 +246,70 @@ targets. Its function is similar to that of :command:`export(...)`.
[VERSION TRUE|FALSE]
)
-Create java documentation based on files or packages. For more
-details please read the javadoc manpage.
-
-There are two main signatures for create_javadoc. The first signature
-works with package names on a path with source files:
-
-::
-
- Example:
- create_javadoc(my_example_doc
- PACKAGES com.example.foo com.example.bar
- SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
- CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
- WINDOWTITLE "My example"
- DOCTITLE "<h1>My example</h1>"
- AUTHOR TRUE
- USE TRUE
- VERSION TRUE
- )
+For example:
+.. code-block:: cmake
+ create_javadoc(my_example_doc
+ PACKAGES com.example.foo com.example.bar
+ SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
+ CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+ WINDOWTITLE "My example"
+ DOCTITLE "<h1>My example</h1>"
+ AUTHOR TRUE
+ USE TRUE
+ VERSION TRUE
+ )
-The second signature for create_javadoc works on a given list of
+The second signature for ``create_javadoc()`` works on a given list of
files.
-::
-
- create_javadoc(<VAR>
- FILES file1 [file2 ...]
- [CLASSPATH <classpath>]
- [INSTALLPATH <install path>]
- [DOCTITLE "the documentation title"]
- [WINDOWTITLE "the title of the document"]
- [AUTHOR TRUE|FALSE]
- [USE TRUE|FALSE]
- [VERSION TRUE|FALSE]
- )
-
-
-
-Example:
-
-::
+.. code-block:: cmake
+
+ create_javadoc(<VAR>
+ FILES <file1> [<file2>...]
+ [CLASSPATH <classpath>]
+ [INSTALLPATH <install path>]
+ [DOCTITLE "the documentation title"]
+ [WINDOWTITLE "the title of the document"]
+ [AUTHOR TRUE|FALSE]
+ [USE TRUE|FALSE]
+ [VERSION TRUE|FALSE]
+ )
- create_javadoc(my_example_doc
- FILES ${example_SRCS}
- CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
- WINDOWTITLE "My example"
- DOCTITLE "<h1>My example</h1>"
- AUTHOR TRUE
- USE TRUE
- VERSION TRUE
- )
+For example:
+.. code-block:: cmake
+ create_javadoc(my_example_doc
+ FILES ${example_SRCS}
+ CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+ WINDOWTITLE "My example"
+ DOCTITLE "<h1>My example</h1>"
+ AUTHOR TRUE
+ USE TRUE
+ VERSION TRUE
+ )
Both signatures share most of the options. These options are the same
as what you can find in the javadoc manpage. Please look at the
-manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and VERSION.
+manpage for ``CLASSPATH``, ``DOCTITLE``, ``WINDOWTITLE``, ``AUTHOR``, ``USE``
+and ``VERSION``.
-The documentation will be by default installed to
+If you don't set the ``INSTALLPATH``, then by default the documentation will
+be installed to :
::
${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
+Header Generation
+^^^^^^^^^^^^^^^^^
-if you don't set the INSTALLPATH.
-
-::
+.. code-block:: cmake
- create_javah(TARGET <target>
- GENERATED_FILES <VAR>
+ create_javah(TARGET <target> | GENERATED_FILES <VAR>
CLASSES <class>...
[CLASSPATH <classpath>...]
[DEPENDS <depend>...]
@@ -384,55 +319,55 @@ if you don't set the INSTALLPATH.
Create C header files from java classes. These files provide the connective glue
that allow your Java and C code to interact.
-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>`_.
-Command ``add_jar(GENERATE_NATIVE_HEADERS)`` must be used instead.
+.. deprecated:: 3.11
-There are two main signatures for create_javah. The first signature
-returns generated files through variable specified by GENERATED_FILES option:
+.. 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.
- Example:
- Create_javah(GENERATED_FILES files_headers
- CLASSES org.cmake.HelloWorld
- CLASSPATH hello.jar
- )
+There are two main signatures for ``create_javah()``. The first signature
+returns generated files through variable specified by the ``GENERATED_FILES``
+option. For example:
+.. code-block:: cmake
+ create_javah(GENERATED_FILES files_headers
+ CLASSES org.cmake.HelloWorld
+ CLASSPATH hello.jar
+ )
-The second signature for create_javah creates a target which encapsulates
-header files generation.
-
-::
-
- Example:
- Create_javah(TARGET target_headers
- CLASSES org.cmake.HelloWorld
- CLASSPATH hello.jar
- )
+The second signature for ``create_javah()`` creates a target which encapsulates
+header files generation. E.g.
+.. code-block:: cmake
+ create_javah(TARGET target_headers
+ CLASSES org.cmake.HelloWorld
+ CLASSPATH hello.jar
+ )
Both signatures share same options.
- ``CLASSES <class>...``
- Specifies Java classes used to generate headers.
+``CLASSES <class>...``
+ Specifies Java classes used to generate headers.
- ``CLASSPATH <classpath>...``
- Specifies various paths to look up classes. Here .class files, jar files or targets
- created by command add_jar can be used.
+``CLASSPATH <classpath>...``
+ Specifies various paths to look up classes. Here .class files, jar files or
+ targets created by command add_jar can be used.
- ``DEPENDS <depend>...``
- Targets on which the javah target depends
+``DEPENDS <depend>...``
+ Targets on which the javah target depends.
- ``OUTPUT_NAME <path>``
- Concatenates the resulting header files for all the classes listed by option CLASSES
- into <path>. Same behavior as option '-o' of javah tool.
+``OUTPUT_NAME <path>``
+ Concatenates the resulting header files for all the classes listed by option
+ ``CLASSES`` into ``<path>``. Same behavior as option ``-o`` of javah tool.
- ``OUTPUT_DIR <path>``
- Sets the directory where the header files will be generated. Same behavior as option
- '-d' of javah tool. If not specified, ${CMAKE_CURRENT_BINARY_DIR} is used as output directory.
+``OUTPUT_DIR <path>``
+ Sets the directory where the header files will be generated. Same behavior
+ as option ``-d`` of javah tool. If not specified,
+ :variable:`CMAKE_CURRENT_BINARY_DIR` is used as the output directory.
#]=======================================================================]
function (__java_copy_file src dest comment)
@@ -800,7 +735,8 @@ function(add_jar _TARGET_NAME)
# this INTERFACE library depends on jar generation
add_dependencies (${_GENERATE_NATIVE_HEADERS_TARGET} ${_TARGET_NAME})
- set_property (DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+ set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES
+ "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
endif()
endfunction()
diff --git a/Modules/UseQt4.cmake b/Modules/UseQt4.cmake
index dc2348ed1..8fec717c0 100644
--- a/Modules/UseQt4.cmake
+++ b/Modules/UseQt4.cmake
@@ -7,8 +7,8 @@ UseQt4
Use Module for QT4
-Sets up C and C++ to use Qt 4. It is assumed that FindQt.cmake has
-already been loaded. See FindQt.cmake for information on how to load
+Sets up C and C++ to use Qt 4. It is assumed that :module:`FindQt` has
+already been loaded. See :module:`FindQt` for information on how to load
Qt 4 into your CMake project.
#]=======================================================================]
@@ -105,4 +105,3 @@ foreach(module QT3SUPPORT QTOPENGL QTASSISTANT QTDESIGNER QTMOTIF QTNSPLUGIN
endif ()
endforeach()
-
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index 18ea55c42..78522da6d 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -466,7 +466,14 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
if(NOT ("-dllimport" IN_LIST swig_source_file_flags OR "-dllimport" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS))
# This makes sure that the name used in the generated DllImport
# matches the library name created by CMake
- list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport" "${name}")
+ list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport" "$<TARGET_FILE_PREFIX:${target_name}>$<TARGET_FILE_BASE_NAME:${target_name}>")
+ endif()
+ endif()
+ if (SWIG_MODULE_${name}_LANGUAGE STREQUAL "PYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY)
+ if(NOT ("-interface" IN_LIST swig_source_file_flags OR "-interface" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS))
+ # This makes sure that the name used in the proxy code
+ # matches the library name created by CMake
+ list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-interface" "$<TARGET_FILE_PREFIX:${target_name}>$<TARGET_FILE_BASE_NAME:${target_name}>")
endif()
endif()
list (APPEND swig_extra_flags ${SWIG_MODULE_${name}_EXTRA_FLAGS})
@@ -701,9 +708,9 @@ function(SWIG_ADD_LIBRARY name)
endif()
endforeach()
set_property (DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES ${swig_generated_sources} ${swig_generated_timestamps})
+ ADDITIONAL_CLEAN_FILES ${swig_generated_sources} ${swig_generated_timestamps})
if (UseSWIG_MODULE_VERSION VERSION_GREATER 1)
- set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${outputdir}")
+ set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${outputdir}")
endif()
add_library(${target_name}
diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake
index 21ccd7ca8..23d81b5fc 100644
--- a/Modules/WriteCompilerDetectionHeader.cmake
+++ b/Modules/WriteCompilerDetectionHeader.cmake
@@ -5,7 +5,7 @@
WriteCompilerDetectionHeader
----------------------------
-This module provides the function write_compiler_detection_header().
+This module provides the function ``write_compiler_detection_header()``.
This function can be used to generate a file suitable for preprocessor
inclusion which contains macros to be used in source code::
diff --git a/Modules/ecos_clean.cmake b/Modules/ecos_clean.cmake
index 21126f624..480b1ce83 100644
--- a/Modules/ecos_clean.cmake
+++ b/Modules/ecos_clean.cmake
@@ -7,10 +7,10 @@ file(GLOB _files ${ECOS_DIR}/*)
# remove all directories, which consist of lower-case letters only
# this skips e.g. CVS/ and .subversion/
foreach(_entry ${_files})
- if(IS_DIRECTORY ${_entry})
- get_filename_component(dir ${_entry} NAME)
- if(${dir} MATCHES "^[a-z]+$")
- file(REMOVE_RECURSE ${_entry})
- endif()
- endif()
+ if(IS_DIRECTORY ${_entry})
+ get_filename_component(dir ${_entry} NAME)
+ if(${dir} MATCHES "^[a-z]+$")
+ file(REMOVE_RECURSE ${_entry})
+ endif()
+ endif()
endforeach()
diff --git a/README.rst b/README.rst
index 775463e9f..76783ec1c 100644
--- a/README.rst
+++ b/README.rst
@@ -57,21 +57,39 @@ You need to have a C++ compiler (supporting C++11) and a ``make`` installed.
Run the ``bootstrap`` script you find in the source directory of CMake.
You can use the ``--help`` option to see the supported options.
You may use the ``--prefix=<install_prefix>`` option to specify a custom
-installation directory for CMake. You can run the ``bootstrap`` script from
-within the CMake source directory or any other build directory of your
-choice. Once this has finished successfully, run ``make`` and
-``make install``. In summary::
+installation directory for CMake. Once this has finished successfully,
+run ``make`` and ``make install``.
- $ ./bootstrap && make && sudo make install
+For example, if you simply want to build and install CMake from source,
+you can build directly in the source tree::
+
+ $ ./bootstrap && make && sudo make install
+
+Or, if you plan to develop CMake or otherwise run the test suite, create
+a separate build tree::
+
+ $ mkdir cmake-build && cd cmake-build
+ $ ../cmake-source/bootstrap && make
Windows
^^^^^^^
-You need to download and install a binary release of CMake in order to build
-CMake. You can get these releases from the `CMake Download Page`_. Then
-proceed with the instructions below.
+There are two ways for building CMake under Windows:
+
+1. Compile with MSVC from VS 2015 or later.
+ You need to download and install a binary release of CMake. You can get
+ these releases from the `CMake Download Page`_. Then proceed with the
+ instructions below for `Building CMake with CMake`_.
+
+2. Bootstrap with MinGW under MSYS2.
+ Download and install `MSYS2`_. Then install the required build tools::
+
+ $ pacman -S --needed git base-devel mingw-w64-x86_64-gcc
+
+ and bootstrap as above.
.. _`CMake Download Page`: https://cmake.org/cmake/resources/software.html
+.. _`MSYS2`: https://www.msys2.org/
Building CMake with CMake
-------------------------
diff --git a/Source/CMakeInstallSignTool.cmake.in b/Source/CMakeInstallSignTool.cmake.in
new file mode 100644
index 000000000..fca629c31
--- /dev/null
+++ b/Source/CMakeInstallSignTool.cmake.in
@@ -0,0 +1,51 @@
+# The signtool. Default to PATH.
+set(CMake_INSTALL_SIGNTOOL "@CMake_INSTALL_SIGNTOOL@")
+if(NOT CMake_INSTALL_SIGNTOOL)
+ set(CMake_INSTALL_SIGNTOOL signtool)
+endif()
+
+# Select a certificate by Subject Name. Default to automatic selection.
+set(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME "@CMake_INSTALL_SIGNTOOL_SUBJECT_NAME@")
+if(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME)
+ set(select_cert -n "${CMake_INSTALL_SIGNTOOL_SUBJECT_NAME}")
+else()
+ set(select_cert -a)
+endif()
+
+# Timestamp URL. Default to a common provider.
+set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "@CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL@")
+if(NOT CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL)
+ set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "http://timestamp.digicert.com")
+endif()
+
+# Glob files that need a signature.
+file(GLOB files "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/*.exe")
+
+# Sign all files at once.
+if(files)
+ # Run the signtool through 'cmd /c' to enable password prompt popup.
+ # Some providers have trouble when signtool is invoked with SW_HIDE.
+ set(cmd cmd /c "${CMake_INSTALL_SIGNTOOL}" sign -v ${select_cert})
+
+ # Sign with SHA-1 for Windows 7 and below.
+ execute_process(
+ COMMAND ${cmd} -t "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+
+ # Sign with SHA-256 for Windows 8 and above.
+ execute_process(
+ COMMAND ${cmd} -tr "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" -fd sha256 -td sha256 -as ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+endif()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1c06052fd..695e07598 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -92,7 +92,6 @@ include_directories(
${CMAKE_ZLIB_INCLUDES}
${CMAKE_EXPAT_INCLUDES}
${CMAKE_TAR_INCLUDES}
- ${CMAKE_COMPRESS_INCLUDES}
${CMake_HAIKU_INCLUDE_DIRS}
)
@@ -144,6 +143,8 @@ set(SRCS
cmAffinity.cxx
cmAffinity.h
cmArchiveWrite.cxx
+ cmArgumentParser.cxx
+ cmArgumentParser.h
cmBase32.cxx
cmCacheManager.cxx
cmCacheManager.h
@@ -225,6 +226,10 @@ set(SRCS
cmFileAPICodemodel.h
cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h
+ cmFileCopier.cxx
+ cmFileCopier.h
+ cmFileInstaller.cxx
+ cmFileInstaller.h
cmFileLock.cxx
cmFileLock.h
cmFileLockPool.cxx
@@ -233,8 +238,12 @@ set(SRCS
cmFileLockResult.h
cmFilePathChecksum.cxx
cmFilePathChecksum.h
- cmFileTimeComparison.cxx
- cmFileTimeComparison.h
+ cmFileTime.cxx
+ cmFileTime.h
+ cmFileTimeCache.cxx
+ cmFileTimeCache.h
+ cmFileTimes.cxx
+ cmFileTimes.h
cmFortranParserImpl.cxx
cmFSPermissions.cxx
cmFSPermissions.h
@@ -257,6 +266,8 @@ set(SRCS
cmGeneratorExpression.h
cmGeneratorTarget.cxx
cmGeneratorTarget.h
+ cmGetPipes.cxx
+ cmGetPipes.h
cmGlobalCommonGenerator.cxx
cmGlobalCommonGenerator.h
cmGlobalGenerator.cxx
@@ -343,10 +354,10 @@ set(SRCS
cmQtAutoGenGlobalInitializer.h
cmQtAutoGenInitializer.cxx
cmQtAutoGenInitializer.h
- cmQtAutoGeneratorMocUic.cxx
- cmQtAutoGeneratorMocUic.h
- cmQtAutoGeneratorRcc.cxx
- cmQtAutoGeneratorRcc.h
+ cmQtAutoMocUic.cxx
+ cmQtAutoMocUic.h
+ cmQtAutoRcc.cxx
+ cmQtAutoRcc.h
cmRST.cxx
cmRST.h
cmScriptGenerator.h
@@ -379,11 +390,16 @@ set(SRCS
cmUuid.cxx
cmUVHandlePtr.cxx
cmUVHandlePtr.h
+ cmUVProcessChain.cxx
+ cmUVProcessChain.h
+ cmUVStreambuf.h
cmUVSignalHackRAII.h
cmVariableWatch.cxx
cmVariableWatch.h
cmVersion.cxx
cmVersion.h
+ cmWorkerPool.cxx
+ cmWorkerPool.h
cmWorkingDirectory.cxx
cmWorkingDirectory.h
cmXMLParser.cxx
@@ -438,8 +454,6 @@ set(SRCS
cmCMakeMinimumRequired.h
cmCMakePolicyCommand.cxx
cmCMakePolicyCommand.h
- cmCommandArgumentsHelper.cxx
- cmCommandArgumentsHelper.h
cmConditionEvaluator.cxx
cmConditionEvaluator.h
cmConfigureFileCommand.cxx
@@ -724,14 +738,6 @@ if (WIN32)
cmVisualStudioSlnParser.cxx
cmVisualStudioWCEPlatformParser.h
cmVisualStudioWCEPlatformParser.cxx
- cmGlobalGhsMultiGenerator.cxx
- cmGlobalGhsMultiGenerator.h
- cmLocalGhsMultiGenerator.cxx
- cmLocalGhsMultiGenerator.h
- cmGhsMultiTargetGenerator.cxx
- cmGhsMultiTargetGenerator.h
- cmGhsMultiGpj.cxx
- cmGhsMultiGpj.h
cmVSSetupHelper.cxx
cmVSSetupHelper.h
)
@@ -751,6 +757,22 @@ if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
)
endif()
+# GHS support
+# Works only for windows and linux
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(SRCS ${SRCS}
+ cmGlobalGhsMultiGenerator.cxx
+ cmGlobalGhsMultiGenerator.h
+ cmLocalGhsMultiGenerator.cxx
+ cmLocalGhsMultiGenerator.h
+ cmGhsMultiTargetGenerator.cxx
+ cmGhsMultiTargetGenerator.h
+ cmGhsMultiGpj.cxx
+ cmGhsMultiGpj.h
+ )
+endif()
+
+
# Ninja support
set(SRCS ${SRCS}
cmGlobalNinjaGenerator.cxx
@@ -766,6 +788,8 @@ set(SRCS ${SRCS}
cmNinjaUtilityTargetGenerator.h
cmNinjaLinkLineComputer.cxx
cmNinjaLinkLineComputer.h
+ cmNinjaLinkLineDeviceComputer.cxx
+ cmNinjaLinkLineDeviceComputer.h
)
# Temporary variable for tools targets
@@ -793,7 +817,7 @@ foreach(check
else()
set(CMake_${check} 0)
endif()
- set_property(SOURCE cmFileTimeComparison.cxx APPEND PROPERTY
+ set_property(SOURCE cmFileTime.cxx APPEND PROPERTY
COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
endforeach()
@@ -801,7 +825,7 @@ endforeach()
add_library(CMakeLib ${SRCS})
target_link_libraries(CMakeLib cmsys
${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
- ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
+ ${CMAKE_TAR_LIBRARIES}
${CMAKE_CURL_LIBRARIES}
${CMAKE_JSONCPP_LIBRARIES}
${CMAKE_LIBUV_LIBRARIES}
@@ -1060,9 +1084,6 @@ if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARI
endif()
if(APPLE)
- add_executable(cmakexbuild cmakexbuild.cxx)
- list(APPEND _tools cmakexbuild)
- target_link_libraries(cmakexbuild CMakeLib)
add_executable(OSXScriptLauncher
CPack/OSXScriptLauncher.cxx)
target_link_libraries(OSXScriptLauncher cmsys)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 01dedde07..ebdb97a29 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 7)
+set(CMake_VERSION_MINOR 15)
+set(CMake_VERSION_PATCH 0)
#set(CMake_VERSION_RC 0)
diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in
index 22b4a3639..762d9bb62 100644
--- a/Source/CMakeVersion.rc.in
+++ b/Source/CMakeVersion.rc.in
@@ -1,25 +1,16 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#define VER_FILEVERSION @CMake_RCVERSION@
-#define VER_FILEVERSION_STR "@CMake_RCVERSION_STR@\0"
-
-#define VER_PRODUCTVERSION @CMake_RCVERSION@
-#define VER_PRODUCTVERSION_STR "@CMake_RCVERSION_STR@\0"
-
-/* Version-information resource identifier. */
-#define VS_VERSION_INFO 1
-
-VS_VERSION_INFO VERSIONINFO
-FILEVERSION VER_FILEVERSION
-PRODUCTVERSION VER_PRODUCTVERSION
+1 VERSIONINFO
+FILEVERSION @CMake_RCVERSION@
+PRODUCTVERSION @CMake_RCVERSION@
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
- VALUE "FileVersion", VER_FILEVERSION_STR
- VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ VALUE "FileVersion", "@CMake_RCVERSION_STR@\0"
+ VALUE "ProductVersion", "@CMake_RCVERSION_STR@\0"
END
END
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index 9102e3e20..c1b6eea9a 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -85,8 +85,8 @@ int cmCPackIFWGenerator::PackageFiles()
int retVal = 1;
cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl);
bool res = cmSystemTools::RunSingleCommand(
- ifwCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(ifwTmpFile);
ofs << "# Run command: " << ifwCmd << std::endl
@@ -198,8 +198,8 @@ int cmCPackIFWGenerator::PackageFiles()
int retVal = 1;
cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl);
bool res = cmSystemTools::RunSingleCommand(
- ifwCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(ifwTmpFile);
ofs << "# Run command: " << ifwCmd << std::endl
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
index 01e3ea4a7..a075a17e3 100644
--- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -152,6 +152,15 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
}
}
+ // StyleSheet
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->StyleSheet = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option);
+ }
+ }
+
// WizardDefaultWidth
if (const char* option =
this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH")) {
@@ -381,6 +390,14 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
xout.Element("WizardStyle", this->WizardStyle);
}
+ // Stylesheet
+ if (!this->StyleSheet.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->StyleSheet);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path);
+ xout.Element("StyleSheet", name);
+ }
+
// WizardDefaultWidth
if (!this->WizardDefaultWidth.empty()) {
xout.Element("WizardDefaultWidth", this->WizardDefaultWidth);
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h
index 37ad339af..be51fa5fb 100644
--- a/Source/CPack/IFW/cmCPackIFWInstaller.h
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.h
@@ -72,6 +72,9 @@ public:
/// Wizard style name
std::string WizardStyle;
+ /// Filename for a style sheet
+ std::string StyleSheet;
+
/// Wizard width
std::string WizardDefaultWidth;
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
index 4966d09f2..00d272c83 100644
--- a/Source/CPack/OSXScriptLauncher.cxx
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -73,7 +73,7 @@ int main(int argc, char* argv[])
args.push_back(nullptr);
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*args.begin());
+ cmsysProcess_SetCommand(cp, args.data());
cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, 0);
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 398ebd399..045d93d87 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -61,9 +61,8 @@ bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
std::string output;
int returnValue = 0;
- bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output,
- &output, &returnValue, 0,
- cmSystemTools::OUTPUT_NONE);
+ bool status = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &returnValue, 0, cmSystemTools::OUTPUT_NONE);
cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
logFile << command << std::endl;
@@ -619,7 +618,7 @@ bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
- if (!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath.c_str())) {
+ if (!ConfigureFile(wixTemplate, mainSourceFilePath)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Failed creating '" << mainSourceFilePath
<< "'' from template." << std::endl);
diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt
deleted file mode 100644
index 1aaf9af51..000000000
--- a/Source/CPack/bills-comments.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-cpack.cxx
-
-cmCPackGenerators -- creates cmCPackGenericGenerator's via NewGenerator
- - a cmCPackGenericGenerator factory
-
-
-cmCPackGenericGenerator::Initialize
- this->InitializeInternal
- CPACK_INCLUDE_TOPLEVEL_DIRECTORY = 0 turns off
-
-
-// binary package run
-cmCPackGenericGenerator::ProcessGenerator // DoPackage
- cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
- cmCPackGenericGenerator::InstallProject
- run preinstall (make preinstall/fast)
- call ReadListFile(cmake_install.cmake)
- glob recurse in install directory to get list of files
- this->CompressFiles with the list of files
-
-
-// source package run
-cmCPackGenericGenerator::ProcessGenerator // DoPackage
- cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
- cmCPackGenericGenerator::InstallProject -->
- if set CPACK_INSTALLED_DIRECTORIES
- glob the files in that directory
- copy those files to the tmp install directory _CPack something
- glob recurse in install directory to get list of files
- this->CompressFiles with the list of files
-
-
-cmCPackGenericGenerator::InstallProject is used for both source and binary
-packages. It is controlled based on values set in CPACK_ variables.
-
-
-InstallProject
- 1. CPACK_INSTALL_COMMANDS - a list of commands used to install the package
-
- 2. CPACK_INSTALLED_DIRECTORIES - copy this directory to CPACK_TEMPORARY_DIRECTORY
-
- 3. CPACK_INSTALL_CMAKE_PROJECTS - a cmake install script
- - run make preinstall
- - run cmake_install.cmake
- - set CMAKE_INSTALL_PREFIX to the temp directory
- - CPACK_BUILD_CONFIG check this and set the BUILD_TYPE to it
- - ReadListFile on the install script cmake_install.cmake
- - run strip on the executables and libraries if CPACK_STRIP_FILES is TRUE
-
-Recommendations:
-
-rename cmCPackGenerators to cmCPackGeneratorFactory
-
-rename cmCPackGenericGenerator --> cmCPackGenerator
-
-rename cmCPackGenericGenerator::ProcessGenerator -> cmCPackGenerator::DoPackage
-
-
-break up cmCPackGenerator::InstallProject so it calls the following:
-
-// run user provided install commands
- cmCPackGenerator::RunInstallCommands();
-// copy entire directories that need no processing like source trees
- cmCPackGenerator::CopyPreInstalledDirectories();
-// run the cmake install scripts if provided
- cmCPackGenerator::RunCMakeInstallScripts()
-
--
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
index 2119f782b..49a9f15c3 100644
--- a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -44,10 +44,9 @@ int cmCPackCygwinBinaryGenerator::PackageFiles()
// to create the file before the super class is called
{
cmGeneratedFileStream ofs(manifestFile.c_str());
- for (std::vector<std::string>::const_iterator i = files.begin();
- i != files.end(); ++i) {
+ for (std::string const& file : files) {
// remove the temp dir and replace with /usr
- ofs << (*i).substr(tempdir.size()) << "\n";
+ ofs << file.substr(tempdir.size()) << "\n";
}
ofs << manifest << "\n";
}
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 635de490a..cfb5efd0e 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -195,7 +195,7 @@ bool DebGenerator::generateDataTar() const
// XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
// should not add XXX/application
orderedFiles.insert(currentPath);
- currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+ currentPath = cmSystemTools::CollapseFullPath("..", currentPath);
}
}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 013ad8163..7a3742b55 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -244,8 +244,8 @@ bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
int exit_code = 1;
bool result = cmSystemTools::RunSingleCommand(
- command.str().c_str(), output, output, &exit_code, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ command.str(), output, output, &exit_code, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!result || exit_code) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index fcf8af1f8..9fdafa47b 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -181,7 +181,7 @@ public:
{
s << "{\n";
for (std::string const& elem : value) {
- s << " \"" << elem << "\": {\"origin\": \"" << elem << "\"},\n";
+ s << " \"" << elem << R"(": {"origin": ")" << elem << "\"},\n";
}
s << '}';
}
@@ -325,8 +325,7 @@ int cmCPackFreeBSDGenerator::PackageFiles()
ONE_PACKAGE_PER_COMPONENT);
}
- std::string output_dir =
- cmSystemTools::CollapseCombinedPath(toplevel, "../");
+ std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(),
manifestname.c_str(), nullptr);
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 57c054590..7e07ff488 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmCryptoHash.h"
#include "cmDuration.h"
#include "cmFSPermissions.h"
+#include "cmFileTimes.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -43,7 +44,8 @@ cmCPackGenerator::~cmCPackGenerator()
this->MakefileMap = nullptr;
}
-void cmCPackGenerator::DisplayVerboseOutput(const char* msg, float progress)
+void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
+ float progress)
{
(void)progress;
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
@@ -278,7 +280,7 @@ int cmCPackGenerator::InstallProjectViaInstallCommands(
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
- ic.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
@@ -387,8 +389,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
}
/* If it is not a symlink then do a plain copy */
else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) &&
- cmSystemTools::CopyFileTime(inFile.c_str(),
- filePath.c_str()))) {
+ cmFileTimes::Copy(inFile, filePath))) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem copying file: " << inFile << " -> "
<< filePath << std::endl);
@@ -647,8 +648,8 @@ int cmCPackGenerator::RunPreinstallTarget(
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
- buildCommand.c_str(), &output, &output, &retVal,
- installDirectory.c_str(), this->GeneratorVerbose, cmDuration::zero());
+ buildCommand, &output, &output, &retVal, installDirectory.c_str(),
+ this->GeneratorVerbose, cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
tmpFile += "/PreinstallOutput.log";
@@ -689,7 +690,7 @@ int cmCPackGenerator::InstallCMakeProject(
cm.SetHomeOutputDirectory("");
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cm.AddCMakePaths();
- cm.SetProgressCallback([this](const char* msg, float prog) {
+ cm.SetProgressCallback([this](const std::string& msg, float prog) {
this->DisplayVerboseOutput(msg, prog);
});
cm.SetTrace(this->Trace);
@@ -1245,7 +1246,8 @@ bool cmCPackGenerator::ConfigureString(const std::string& inString,
return true;
}
-bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
+bool cmCPackGenerator::ConfigureFile(const std::string& inName,
+ const std::string& outName,
bool copyOnly /* = false */)
{
return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
@@ -1254,9 +1256,8 @@ bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
int cmCPackGenerator::CleanTemporaryDirectory()
{
- std::string tempInstallDirectoryWithPostfix =
+ std::string tempInstallDirectory =
this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
- const char* tempInstallDirectory = tempInstallDirectoryWithPostfix.c_str();
if (cmsys::SystemTools::FileExists(tempInstallDirectory)) {
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Clean temporary : " << tempInstallDirectory << std::endl);
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 4755f942b..3c06d4196 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -96,7 +96,7 @@ public:
void SetLogger(cmCPackLog* log) { this->Logger = log; }
//! Display verbose information via logger
- void DisplayVerboseOutput(const char* msg, float progress);
+ void DisplayVerboseOutput(const std::string& msg, float progress);
bool ReadListFile(const char* moduleName);
@@ -169,7 +169,8 @@ protected:
virtual const char* GetPackagingInstallPrefix();
virtual std::string FindTemplate(const char* name);
- virtual bool ConfigureFile(const char* inName, const char* outName,
+ virtual bool ConfigureFile(const std::string& inName,
+ const std::string& outName,
bool copyOnly = false);
virtual bool ConfigureString(const std::string& input, std::string& output);
virtual int InitializeInternal();
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
index 7f633e473..972f0f73c 100644
--- a/Source/CPack/cmCPackGeneratorFactory.h
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -22,6 +22,9 @@ public:
cmCPackGeneratorFactory();
~cmCPackGeneratorFactory();
+ cmCPackGeneratorFactory(const cmCPackGeneratorFactory&) = delete;
+ cmCPackGeneratorFactory& operator=(const cmCPackGeneratorFactory&) = delete;
+
//! Get the generator
cmCPackGenerator* NewGenerator(const std::string& name);
void DeleteGenerator(cmCPackGenerator* gen);
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
index 8e9922121..65281e3d8 100644
--- a/Source/CPack/cmCPackLog.h
+++ b/Source/CPack/cmCPackLog.h
@@ -26,6 +26,9 @@ public:
cmCPackLog();
~cmCPackLog();
+ cmCPackLog(const cmCPackLog&) = delete;
+ cmCPackLog& operator=(const cmCPackLog&) = delete;
+
enum __log_tags
{
NOTAG = 0,
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 37ea66e76..e2020c5ae 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -182,7 +182,7 @@ int cmCPackNSISGenerator::PackageFiles()
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
- "File /r \"${INST_DIR}\\*.*\"");
+ R"(File /r "${INST_DIR}\*.*")");
this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
@@ -242,7 +242,7 @@ int cmCPackNSISGenerator::PackageFiles()
}
// Add this component to the various section lists.
- sectionList += " !insertmacro \"${MacroName}\" \"";
+ sectionList += R"( !insertmacro "${MacroName}" ")";
sectionList += comp.first;
sectionList += "\"\n";
selectedVarsList += "Var " + comp.first + "_selected\n";
@@ -292,9 +292,8 @@ int cmCPackNSISGenerator::PackageFiles()
this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
}
- this->ConfigureFile(nsisInInstallOptions.c_str(),
- nsisInstallOptions.c_str());
- this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
+ this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
+ this->ConfigureFile(nsisInFileName, nsisFileName);
std::string nsisCmd = "\"";
nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
nsisCmd += "\" \"" + nsisFileName + "\"";
@@ -302,8 +301,8 @@ int cmCPackNSISGenerator::PackageFiles()
std::string output;
int retVal = 1;
bool res = cmSystemTools::RunSingleCommand(
- nsisCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(tmpFile);
ofs << "# Run command: " << nsisCmd << std::endl
@@ -407,8 +406,8 @@ int cmCPackNSISGenerator::InitializeInternal()
std::string output;
int retVal = 1;
bool resS = cmSystemTools::RunSingleCommand(
- nsisCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
if (!resS || retVal ||
@@ -495,10 +494,10 @@ int cmCPackNSISGenerator::InitializeInternal()
std::string execName = *it;
++it;
std::string linkName = *it;
- str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
<< execName << ".exe\"" << std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".lnk\"" << std::endl;
// see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
// if so add a desktop link
@@ -508,7 +507,7 @@ int cmCPackNSISGenerator::InitializeInternal()
execName) != cpackPackageDesktopLinksVector.end()) {
str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
str << " CreateShortCut \"$DESKTOP\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
<< execName << ".exe\"" << std::endl;
deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
@@ -564,15 +563,15 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
++it;
std::string linkName = *it;
if (!url) {
- str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".lnk\"" << std::endl;
} else {
- str << " WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".url\" \"InternetShortcut\" \"URL\" \"" << sourceName << "\""
+ str << R"( WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.url" "InternetShortcut" "URL" ")" << sourceName << "\""
<< std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".url\"" << std::endl;
}
// see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
@@ -582,7 +581,7 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
if (this->IsSet(desktop)) {
str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
str << " CreateShortCut \"$DESKTOP\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
<< std::endl;
@@ -749,7 +748,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
std::string output;
int retVal = -1;
int res = cmSystemTools::RunSingleCommand(
- cmd.c_str(), &output, &output, &retVal, dirName.c_str(),
+ cmd, &output, &output, &retVal, dirName.c_str(),
cmSystemTools::OUTPUT_NONE, cmDuration::zero());
if (!res || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
index 486633c90..90e0afe7f 100644
--- a/Source/CPack/cmCPackOSXX11Generator.cxx
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -83,7 +83,7 @@ int cmCPackOSXX11Generator::PackageFiles()
return 0;
}
std::string destFileName = resourcesDirectory + "/" + iconFileName;
- this->ConfigureFile(iconFile, destFileName.c_str(), true);
+ this->ConfigureFile(iconFile, destFileName, true);
this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
}
@@ -155,8 +155,8 @@ int cmCPackOSXX11Generator::PackageFiles()
bool res = false;
while (numTries > 0) {
res = cmSystemTools::RunSingleCommand(
- dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (res && !retVal) {
numTries = -1;
break;
@@ -236,7 +236,7 @@ bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name)
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
<< (inFileName ? inFileName : "(NULL)")
<< " to " << destFileName << std::endl);
- this->ConfigureFile(inFileName, destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
*/
@@ -266,7 +266,7 @@ bool cmCPackOSXX11Generator::CopyResourcePlistFile(
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << inFileName << " to " << destFileName
<< std::endl);
- this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly);
+ this->ConfigureFile(inFileName, destFileName, copyOnly);
return true;
}
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
index ae227aab1..8c22c65b0 100644
--- a/Source/CPack/cmCPackPKGGenerator.cxx
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -66,21 +66,17 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
xout.StartElement("choices-outline");
// Emit the outline for the groups
- std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
- for (groupIt = this->ComponentGroups.begin();
- groupIt != this->ComponentGroups.end(); ++groupIt) {
- if (groupIt->second.ParentGroup == nullptr) {
- CreateChoiceOutline(groupIt->second, xout);
+ for (auto const& group : this->ComponentGroups) {
+ if (group.second.ParentGroup == nullptr) {
+ CreateChoiceOutline(group.second, xout);
}
}
// Emit the outline for the non-grouped components
- std::map<std::string, cmCPackComponent>::iterator compIt;
- for (compIt = this->Components.begin(); compIt != this->Components.end();
- ++compIt) {
- if (!compIt->second.Group) {
+ for (auto const& comp : this->Components) {
+ if (!comp.second.Group) {
xout.StartElement("line");
- xout.Attribute("choice", compIt->first + "Choice");
+ xout.Attribute("choice", comp.first + "Choice");
xout.Content(""); // Avoid self-closing tag.
xout.EndElement();
}
@@ -94,13 +90,11 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
xout.EndElement(); // choices-outline>
// Create the actual choices
- for (groupIt = this->ComponentGroups.begin();
- groupIt != this->ComponentGroups.end(); ++groupIt) {
- CreateChoice(groupIt->second, xout);
+ for (auto const& group : this->ComponentGroups) {
+ CreateChoice(group.second, xout);
}
- for (compIt = this->Components.begin(); compIt != this->Components.end();
- ++compIt) {
- CreateChoice(compIt->second, xout);
+ for (auto const& comp : this->Components) {
+ CreateChoice(comp.second, xout);
}
if (!this->PostFlightComponent.Name.empty()) {
@@ -111,7 +105,7 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
// Create the distribution.dist file in the metapackage to turn it
// into a distribution package.
- this->ConfigureFile(distributionTemplate.c_str(), distributionFile.c_str());
+ this->ConfigureFile(distributionTemplate, distributionFile);
}
void cmCPackPKGGenerator::CreateChoiceOutline(
@@ -119,17 +113,13 @@ void cmCPackPKGGenerator::CreateChoiceOutline(
{
xout.StartElement("line");
xout.Attribute("choice", group.Name + "Choice");
- std::vector<cmCPackComponentGroup*>::const_iterator groupIt;
- for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();
- ++groupIt) {
- CreateChoiceOutline(**groupIt, xout);
+ for (cmCPackComponentGroup* subgroup : group.Subgroups) {
+ CreateChoiceOutline(*subgroup, xout);
}
- std::vector<cmCPackComponent*>::const_iterator compIt;
- for (compIt = group.Components.begin(); compIt != group.Components.end();
- ++compIt) {
+ for (cmCPackComponent* comp : group.Components) {
xout.StartElement("line");
- xout.Attribute("choice", (*compIt)->Name + "Choice");
+ xout.Attribute("choice", comp->Name + "Choice");
xout.Content(""); // Avoid self-closing tag.
xout.EndElement();
}
@@ -238,11 +228,9 @@ void cmCPackPKGGenerator::AddDependencyAttributes(
}
visited.insert(&component);
- std::vector<cmCPackComponent*>::const_iterator dependIt;
- for (dependIt = component.Dependencies.begin();
- dependIt != component.Dependencies.end(); ++dependIt) {
- out << " && choices['" << (*dependIt)->Name << "Choice'].selected";
- AddDependencyAttributes(**dependIt, visited, out);
+ for (cmCPackComponent* depend : component.Dependencies) {
+ out << " && choices['" << depend->Name << "Choice'].selected";
+ AddDependencyAttributes(*depend, visited, out);
}
}
@@ -255,11 +243,9 @@ void cmCPackPKGGenerator::AddReverseDependencyAttributes(
}
visited.insert(&component);
- std::vector<cmCPackComponent*>::const_iterator dependIt;
- for (dependIt = component.ReverseDependencies.begin();
- dependIt != component.ReverseDependencies.end(); ++dependIt) {
- out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
- AddReverseDependencyAttributes(**dependIt, visited, out);
+ for (cmCPackComponent* depend : component.ReverseDependencies) {
+ out << " || choices['" << depend->Name << "Choice'].selected";
+ AddReverseDependencyAttributes(*depend, visited, out);
}
}
@@ -308,7 +294,7 @@ bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << (inFileName ? inFileName : "(NULL)")
<< " to " << destFileName << std::endl);
- this->ConfigureFile(inFileName, destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
@@ -336,7 +322,7 @@ bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << inFileName << " to " << destFileName
<< std::endl);
- this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
index 246178d8f..3d93c48f1 100644
--- a/Source/CPack/cmCPackPackageMakerGenerator.cxx
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -295,8 +295,8 @@ int cmCPackPackageMakerGenerator::PackageFiles()
bool res = false;
while (numTries > 0) {
res = cmSystemTools::RunSingleCommand(
- dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (res && !retVal) {
numTries = -1;
break;
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
index a556e0c52..94b5b5f7e 100644
--- a/Source/CPack/cmCPackProductBuildGenerator.cxx
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -145,8 +145,8 @@ bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
std::string output;
int retVal = 1;
bool res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
if (!res || retVal) {
cmGeneratedFileStream ofs(tmpFile);
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 0413422b2..58b9e70fa 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -82,7 +82,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue,
return 0;
}
std::string key = value.substr(0, pos);
- value = value.c_str() + pos + 1;
+ value = value.substr(pos + 1);
def->Map[key] = value;
cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
"Set CPack variable: " << key << " to \"" << value << "\""
@@ -90,7 +90,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue,
return 1;
}
-static void cpackProgressCallback(const char* message, float /*unused*/)
+static void cpackProgressCallback(const std::string& message, float /*unused*/)
{
std::cout << "-- " << message << std::endl;
}
@@ -98,6 +98,7 @@ static void cpackProgressCallback(const char* message, float /*unused*/)
// this is CPack.
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index b154caf30..b957856e8 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBZR.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -242,7 +243,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
@@ -365,7 +366,7 @@ bool cmCTestBZR::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 2fd4c7ab3..9ad96699b 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -118,7 +118,7 @@ public:
: CM(cm)
{
cmSystemTools::SetMessageCallback(
- [&s](const char* msg, const char* /*unused*/) {
+ [&s](const std::string& msg, const char* /*unused*/) {
s += msg;
s += "\n";
});
@@ -126,9 +126,11 @@ public:
cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
- this->CM.SetProgressCallback([&s](const char* msg, float /*unused*/) {
- s += msg;
- s += "\n";
+ this->CM.SetProgressCallback([&s](const std::string& msg, float prog) {
+ if (prog < 0) {
+ s += msg;
+ s += "\n";
+ }
});
}
@@ -139,6 +141,11 @@ public:
cmSystemTools::SetStdoutCallback(nullptr);
cmSystemTools::SetMessageCallback(nullptr);
}
+
+ cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
+ delete;
+ cmCTestBuildAndTestCaptureRAII& operator=(
+ const cmCTestBuildAndTestCaptureRAII&) = delete;
};
int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
@@ -250,7 +257,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
}
int retVal = cm.GetGlobalGenerator()->Build(
cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
- this->BuildProject, tar, output, this->BuildMakeProgram, config,
+ this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
!this->BuildNoClean, false, false, remainingTime);
out << output;
// if the build failed then return
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
index 5e6d0aad2..2d47b1580 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -44,7 +44,7 @@ public:
void Initialize() override;
protected:
- ///! Run CMake and build a test and then run it as a single test.
+ //! Run CMake and build a test and then run it as a single test.
int RunCMakeAndTest(std::string* output);
int RunCMake(std::string* outstring, std::ostringstream& out,
std::string& cmakeOutString, cmake* cm);
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 32f7496a9..2eacaf144 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -4,7 +4,6 @@
#include "cmCTest.h"
#include "cmCTestBuildHandler.h"
-#include "cmCTestGenericHandler.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -39,12 +38,10 @@ cmCTestBuildCommand::~cmCTestBuildCommand()
cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("build");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate build handler");
- return nullptr;
- }
- this->Handler = static_cast<cmCTestBuildHandler*>(handler);
+ cmCTestBuildHandler* handler = this->CTest->GetBuildHandler();
+ handler->Initialize();
+
+ this->Handler = handler;
const char* ctestBuildCommand =
this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index d934c003c..c8e4fa1b4 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -5,7 +5,7 @@
#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmDuration.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
#include "cmMakefile.h"
#include "cmProcessOutput.h"
@@ -32,13 +32,13 @@ static const char* cmCTestErrorMatches[] = {
"^Error: ",
"^Error ",
"[0-9] ERROR: ",
- "^\"[^\"]+\", line [0-9]+: [^Ww]",
+ R"(^"[^"]+", line [0-9]+: [^Ww])",
"^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*ERROR([^:])*:",
- "^ild:([ \\t])*\\(undefined symbol\\)",
+ R"(^ild:([ \t])*\(undefined symbol\))",
"([^ :]+) : (error|fatal error|catastrophic error)",
"([^:]+): (Error:|error|undefined reference|multiply defined)",
- "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)",
+ R"(([^:]+)\(([^\)]+)\) ?: (error|fatal error|catastrophic error))",
"^fatal error C[0-9]+:",
": syntax error ",
"^collect2: ld returned 1 exit status",
@@ -50,14 +50,14 @@ static const char* cmCTestErrorMatches[] = {
"^CMake Error.*:",
":[ \\t]cannot find",
":[ \\t]can't find",
- ": \\*\\*\\* No rule to make target [`'].*\\'. Stop",
- ": \\*\\*\\* No targets specified and no makefile found",
+ R"(: \*\*\* No rule to make target [`'].*\'. Stop)",
+ R"(: \*\*\* No targets specified and no makefile found)",
": Invalid loader fixup for symbol",
": Invalid fixups exist",
": Can't find library for",
": internal link edit command failed",
": Unrecognized option [`'].*\\'",
- "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([^WI]\\)",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([^WI]\))",
"ld: 0706-006 Cannot find or open library file: -l ",
"ild: \\(argument error\\) can't find library argument ::",
"^could not be found and will not be loaded.",
@@ -66,11 +66,11 @@ static const char* cmCTestErrorMatches[] = {
"ld: 0711-993 Error occurred while writing to the output file:",
"ld: fatal: ",
"final link failed:",
- "make: \\*\\*\\*.*Error",
- "make\\[.*\\]: \\*\\*\\*.*Error",
- "\\*\\*\\* Error code",
+ R"(make: \*\*\*.*Error)",
+ R"(make\[.*\]: \*\*\*.*Error)",
+ R"(\*\*\* Error code)",
"nternal error:",
- "Makefile:[0-9]+: \\*\\*\\* .* Stop\\.",
+ R"(Makefile:[0-9]+: \*\*\* .* Stop\.)",
": No such file or directory",
": Invalid argument",
"^The project cannot be built\\.",
@@ -101,19 +101,19 @@ static const char* cmCTestWarningMatches[] = {
"^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*WARNING([^:])*:",
"([^:]+): warning ([0-9]+):",
- "^\"[^\"]+\", line [0-9]+: [Ww](arning|arnung)",
+ R"(^"[^"]+", line [0-9]+: [Ww](arning|arnung))",
"([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
"^(Warning|Warnung) ([0-9]+):",
"^(Warning|Warnung)[ :]",
"WARNING: ",
"([^ :]+) : warning",
"([^:]+): warning",
- "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([WI]\\)",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([WI]\))",
"^cxx: Warning:",
".*file: .* has no symbols",
"([^ :]+):([0-9]+): (Warning|Warnung)",
"\\([0-9]*\\): remark #[0-9]*",
- "\".*\", line [0-9]+: remark\\([0-9]*\\):",
+ R"(".*", line [0-9]+: remark\([0-9]*\):)",
"cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
"^CMake Warning.*:",
"^\\[WARNING\\]",
@@ -121,9 +121,9 @@ static const char* cmCTestWarningMatches[] = {
};
static const char* cmCTestWarningExceptions[] = {
- "/usr/.*/X11/Xlib\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
- "/usr/.*/X11/Xutil\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
- "/usr/.*/X11/XResource\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
+ R"(/usr/.*/X11/Xlib\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/Xutil\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/XResource\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
"WARNING 84 :",
"WARNING 47 :",
"makefile:",
@@ -150,8 +150,8 @@ struct cmCTestBuildCompileErrorWarningRex
static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = {
{ "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
{ "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
- { "^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
- { "^[0-9]+>([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { R"(^([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
+ { R"(^[0-9]+>([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
{ "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
{ "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
{ "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
@@ -387,7 +387,7 @@ int cmCTestBuildHandler::ProcessHandler()
std::string srcdirrep;
for (cc = srcdir.size() - 2; cc > 0; cc--) {
if (srcdir[cc] == '/') {
- srcdirrep = srcdir.c_str() + cc;
+ srcdirrep = srcdir.substr(cc);
srcdirrep = "/..." + srcdirrep;
srcdir = srcdir.substr(0, cc + 1);
break;
@@ -401,7 +401,7 @@ int cmCTestBuildHandler::ProcessHandler()
std::string bindirrep;
for (cc = bindir.size() - 2; cc > 0; cc--) {
if (bindir[cc] == '/') {
- bindirrep = bindir.c_str() + cc;
+ bindirrep = bindir.substr(cc);
bindirrep = "/..." + bindirrep;
bindir = bindir.substr(0, cc + 1);
break;
@@ -418,8 +418,8 @@ int cmCTestBuildHandler::ProcessHandler()
int retVal = 0;
int res = cmsysProcess_State_Exited;
if (!this->CTest->GetShowOnly()) {
- res = this->RunMakeCommand(makeCommand.c_str(), &retVal,
- buildDirectory.c_str(), 0, ofs);
+ res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
+ ofs);
} else {
cmCTestOptionalLog(this->CTest, DEBUG,
"Build with command: " << makeCommand << std::endl,
@@ -503,7 +503,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
class cmCTestBuildHandler::FragmentCompare
{
public:
- FragmentCompare(cmFileTimeComparison* ftc)
+ FragmentCompare(cmFileTimeCache* ftc)
: FTC(ftc)
{
}
@@ -513,14 +513,14 @@ public:
// Order files by modification time. Use lexicographic order
// among files with the same time.
int result;
- if (this->FTC->FileTimeCompare(l, r, &result) && result != 0) {
+ if (this->FTC->Compare(l, r, &result) && result != 0) {
return result < 0;
}
return l < r;
}
private:
- cmFileTimeComparison* FTC = nullptr;
+ cmFileTimeCache* FTC = nullptr;
};
void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
@@ -530,7 +530,7 @@ void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
}
// Sort XML fragments in chronological order.
- cmFileTimeComparison ftc;
+ cmFileTimeCache ftc;
FragmentCompare fragmentCompare(&ftc);
typedef std::set<std::string, FragmentCompare> Fragments;
Fragments fragments(fragmentCompare);
@@ -680,6 +680,8 @@ class cmCTestBuildHandler::LaunchHelper
public:
LaunchHelper(cmCTestBuildHandler* handler);
~LaunchHelper();
+ LaunchHelper(const LaunchHelper&) = delete;
+ LaunchHelper& operator=(const LaunchHelper&) = delete;
private:
cmCTestBuildHandler* Handler;
@@ -764,9 +766,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
}
}
-int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
- const char* dir, int timeout,
- std::ostream& ofs, Encoding encoding)
+int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
+ int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding)
{
// First generate the command and arguments
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
@@ -800,7 +803,7 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, timeout);
@@ -975,10 +978,9 @@ void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length,
if (it != queue->end()) {
// Create a contiguous array for the line
this->CurrentProcessingLine.clear();
- this->CurrentProcessingLine.insert(this->CurrentProcessingLine.end(),
- queue->begin(), it);
+ cmAppend(this->CurrentProcessingLine, queue->begin(), it);
this->CurrentProcessingLine.push_back(0);
- const char* line = &*this->CurrentProcessingLine.begin();
+ const char* line = this->CurrentProcessingLine.data();
// Process the line
int lineType = this->ProcessSingleLine(line);
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index a9b121b24..722c59009 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -52,7 +52,7 @@ private:
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
- int RunMakeCommand(const char* command, int* retVal, const char* dir,
+ int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
int timeout, std::ostream& ofs,
Encoding encoding = cmProcessOutput::Auto);
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 6e8f73f83..9c038399e 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -78,7 +78,7 @@ bool cmCTestCVS::UpdateImpl()
opts = "-dP";
}
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// Specify the start time for nightly testing.
if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index 7b5c3bcb5..74a932a65 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -3,7 +3,7 @@
#include "cmCTestConfigureCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestConfigureHandler.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -142,13 +142,8 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
labelsForSubprojects, this->Quiet);
}
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("configure");
- if (!handler) {
- this->SetError(
- "internal CTest error. Cannot instantiate configure handler");
- return nullptr;
- }
+ cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler();
+ handler->Initialize();
handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index 6b7601b6e..7e93189cd 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -61,7 +61,7 @@ int cmCTestConfigureHandler::ProcessHandler()
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Configure with command: " << cCommand << std::endl,
this->Quiet);
- res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+ res = this->CTest->RunMakeCommand(cCommand, output, &retVal,
buildDirectory.c_str(),
cmDuration::zero(), ofs);
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index d2003baa3..07aae768c 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -19,12 +19,8 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
this->Quiet);
- cmCTestCoverageHandler* handler = static_cast<cmCTestCoverageHandler*>(
- this->CTest->GetInitializedHandler("coverage"));
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate test handler");
- return nullptr;
- }
+ cmCTestCoverageHandler* handler = this->CTest->GetCoverageHandler();
+ handler->Initialize();
// If a LABELS option was given, select only files with the labels.
if (this->LabelsMentioned) {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 225383ce0..f6028c4fc 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCoverageHandler.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmDuration.h"
#include "cmGeneratedFileStream.h"
@@ -52,6 +53,8 @@ public:
}
cmsysProcess_Delete(this->Process);
}
+ cmCTestRunProcess(const cmCTestRunProcess&) = delete;
+ cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
void SetCommand(const char* command)
{
this->CommandLineStrings.clear();
@@ -72,7 +75,7 @@ public:
args.push_back(cl.c_str());
}
args.push_back(nullptr); // null terminate
- cmsysProcess_SetCommand(this->Process, &*args.begin());
+ cmsysProcess_SetCommand(this->Process, args.data());
if (!this->WorkingDirectory.empty()) {
cmsysProcess_SetWorkingDirectory(this->Process,
this->WorkingDirectory.c_str());
@@ -223,7 +226,7 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file,
checkDir = fBinDir;
}
std::string ndc = cmSystemTools::FileExistsInParentDirectories(
- ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ ".NoDartCoverage", fFile, checkDir);
if (!ndc.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Found: " << ndc << " so skip coverage of " << file
@@ -254,8 +257,8 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file,
return true;
}
- ndc = cmSystemTools::FileExistsInParentDirectories(
- ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage", fFile,
+ checkDir);
if (!ndc.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Found: " << ndc << " so skip coverage of: " << file
@@ -786,6 +789,9 @@ struct cmCTestCoverageHandlerLocale
cmSystemTools::UnsetEnv("LC_ALL");
}
}
+ cmCTestCoverageHandlerLocale(const cmCTestCoverageHandlerLocale&) = delete;
+ cmCTestCoverageHandlerLocale& operator=(
+ const cmCTestCoverageHandlerLocale&) = delete;
std::string lc_all;
};
@@ -808,15 +814,11 @@ int cmCTestCoverageHandler::HandleJacocoCoverage(
// ...and in the binary directory.
cmsys::Glob g2;
- std::vector<std::string> binFiles;
g2.SetRecurse(true);
std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
std::string binCoverageFile = binaryDir + "/*jacoco.xml";
g2.FindFiles(binCoverageFile);
- binFiles = g2.GetFiles();
- if (!binFiles.empty()) {
- files.insert(files.end(), binFiles.begin(), binFiles.end());
- }
+ cmAppend(files, g2.GetFiles());
if (!files.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -999,7 +1001,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
static_cast<void>(locale_C);
std::vector<std::string> basecovargs =
- cmSystemTools::ParseArguments(gcovExtraFlags.c_str());
+ cmSystemTools::ParseArguments(gcovExtraFlags);
basecovargs.insert(basecovargs.begin(), gcovCommand);
basecovargs.emplace_back("-o");
@@ -1058,8 +1060,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
this->Quiet);
std::vector<std::string> lines;
-
- cmSystemTools::Split(output.c_str(), lines);
+ cmsys::SystemTools::Split(output, lines);
for (std::string const& line : lines) {
std::string sourceFile;
@@ -1373,7 +1374,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
static_cast<void>(locale_C);
std::vector<std::string> covargs =
- cmSystemTools::ParseArguments(lcovExtraFlags.c_str());
+ cmSystemTools::ParseArguments(lcovExtraFlags);
covargs.insert(covargs.begin(), lcovCommand);
const std::string command = joinCommandLine(covargs);
@@ -1435,8 +1436,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
this->Quiet);
std::vector<std::string> lines;
-
- cmSystemTools::Split(output.c_str(), lines);
+ cmsys::SystemTools::Split(output, lines);
for (std::string const& line : lines) {
std::string sourceFile;
@@ -1462,8 +1462,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
" looking for LCOV files in: " << daGlob << std::endl, this->Quiet);
gl.FindFiles(daGlob);
// Keep a list of all LCOV files
- lcovFiles.insert(lcovFiles.end(), gl.GetFiles().begin(),
- gl.GetFiles().end());
+ cmAppend(lcovFiles, gl.GetFiles());
for (std::string const& file : lcovFiles) {
lcovFile = file;
@@ -1601,11 +1600,11 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
std::string daGlob = lm.first;
daGlob += "/*.da";
gl.FindFiles(daGlob);
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
daGlob = lm.first;
daGlob += "/*.gcda";
gl.FindFiles(daGlob);
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
}
}
@@ -1642,7 +1641,7 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
"Error while finding files matching " << daGlob << std::endl);
return false;
}
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Now searching in: " << daGlob << std::endl, this->Quiet);
return true;
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
index 6eb43546d..cc63e4563 100644
--- a/Source/CTest/cmCTestCurl.cxx
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCurl.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCurl.h"
#include "cmSystemTools.h"
@@ -43,19 +44,15 @@ size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
void* data)
{
int realsize = static_cast<int>(size * nmemb);
-
- std::vector<char>* vec = static_cast<std::vector<char>*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
+ cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize);
return realsize;
}
size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
char* chPtr, size_t size, void* data)
{
- std::vector<char>* vec = static_cast<std::vector<char>*>(data);
- vec->insert(vec->end(), chPtr, chPtr + size);
-
+ cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size);
return size;
}
}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
index 86d948995..6186af8d2 100644
--- a/Source/CTest/cmCTestCurl.h
+++ b/Source/CTest/cmCTestCurl.h
@@ -16,6 +16,8 @@ class cmCTestCurl
public:
cmCTestCurl(cmCTest*);
~cmCTestCurl();
+ cmCTestCurl(const cmCTestCurl&) = delete;
+ cmCTestCurl& operator=(const cmCTestCurl&) = delete;
bool UploadFile(std::string const& local_file, std::string const& url,
std::string const& fields, std::string& response);
bool HttpRequest(std::string const& url, std::string const& fields,
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 210abe55b..9d9761ce2 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -162,7 +162,7 @@ bool cmCTestGIT::UpdateByFetchAndReset()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
git_fetch.push_back(arg.c_str());
}
@@ -547,7 +547,7 @@ private:
{
// Look for header fields that we need.
if (cmHasLiteralPrefix(this->Line, "commit ")) {
- this->Rev.Rev = this->Line.c_str() + 7;
+ this->Rev.Rev = this->Line.substr(7);
} else if (cmHasLiteralPrefix(this->Line, "author ")) {
Person author;
this->ParsePerson(this->Line.c_str() + 7, author);
diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx
index a2d4d2c75..54ebd4f0c 100644
--- a/Source/CTest/cmCTestGlobalVC.cxx
+++ b/Source/CTest/cmCTestGlobalVC.cxx
@@ -117,3 +117,8 @@ bool cmCTestGlobalVC::WriteXMLUpdates(cmXMLWriter& xml)
return result;
}
+
+void cmCTestGlobalVC::SetNewRevision(std::string const& revision)
+{
+ this->NewRevision = revision;
+}
diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h
index 76377ed17..9c572152e 100644
--- a/Source/CTest/cmCTestGlobalVC.h
+++ b/Source/CTest/cmCTestGlobalVC.h
@@ -32,6 +32,8 @@ protected:
// Implement cmCTestVC internal API.
bool WriteXMLUpdates(cmXMLWriter& xml) override;
+ void SetNewRevision(std::string const& revision) override;
+
/** Represent a vcs-reported action for one path in a revision. */
struct Change
{
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 6fb99d864..ba2252a30 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestHG.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -144,7 +145,7 @@ bool cmCTestHG::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
hg_update.push_back(arg.c_str());
}
@@ -202,7 +203,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 57a14efd1..adf955399 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -76,6 +76,8 @@ public:
}
}
}
+ SaveRestoreErrorState(const SaveRestoreErrorState&) = delete;
+ SaveRestoreErrorState& operator=(const SaveRestoreErrorState&) = delete;
private:
bool InitialErrorState;
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 5e66e056a..a96513e8c 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -308,7 +308,7 @@ void cmCTestLaunch::LoadLabels()
if (line[0] == ' ') {
// Label lines appear indented by one space.
if (inTarget || inSource) {
- this->Labels.insert(line.c_str() + 1);
+ this->Labels.insert(line.substr(1));
}
} else if (!this->OptionSource.empty() && !inSource) {
// Non-indented lines specify a source file name. The first one
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index debbe59d7..107fd6174 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -28,6 +28,9 @@ private:
cmCTestLaunch(int argc, const char* const* argv);
~cmCTestLaunch();
+ cmCTestLaunch(const cmCTestLaunch&) = delete;
+ cmCTestLaunch& operator=(const cmCTestLaunch&) = delete;
+
// Run the real command.
int Run();
void RunChild();
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index a5d599583..7dad1cec5 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -7,7 +7,6 @@
#include <vector>
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestMemCheckHandler.h"
#include "cmMakefile.h"
@@ -20,8 +19,8 @@ cmCTestMemCheckCommand::cmCTestMemCheckCommand()
cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
{
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("memcheck");
+ cmCTestMemCheckHandler* handler = this->CTest->GetMemCheckHandler();
+ handler->Initialize();
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 8ba59d3f9..b09e7bb22 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -520,7 +520,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
}
this->MemoryTesterOptions =
- cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
+ cmSystemTools::ParseArguments(memoryTesterOptions);
this->MemoryTesterOutputFile =
this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
@@ -725,7 +725,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
int defects = 0;
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
std::ostringstream ostr;
log.clear();
for (std::string const& l : lines) {
@@ -755,7 +755,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
const std::string& str, std::string& log, std::vector<int>& results)
{
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
std::ostringstream ostr;
log.clear();
@@ -798,7 +798,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
const std::string& str, std::string& log, std::vector<int>& results)
{
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
bool unlimitedOutput = false;
if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
this->CustomMaximumFailedTestOutputSize == 0) {
@@ -815,9 +815,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
cmsys::RegularExpression vgFIM(
- "== .*Invalid free\\(\\) / delete / delete\\[\\]");
+ R"(== .*Invalid free\(\) / delete / delete\[\])");
cmsys::RegularExpression vgFMM(
- "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
+ R"(== .*Mismatched free\(\) / delete / delete \[\])");
cmsys::RegularExpression vgMLK1(
"== .*[0-9,]+ bytes in [0-9,]+ blocks are definitely lost"
" in loss record [0-9,]+ of [0-9,]+");
@@ -937,7 +937,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
log.clear();
auto sttime = std::chrono::steady_clock::now();
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
cmCTestOptionalLog(this->CTest, DEBUG,
"Start test: " << lines.size() << std::endl, this->Quiet);
std::vector<std::string>::size_type cc;
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 8880dac9a..746d72c01 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -114,7 +114,7 @@ private:
// this type of checker
void InitializeResultsVectors();
- ///! Initialize memory checking subsystem.
+ //! Initialize memory checking subsystem.
bool InitializeMemoryChecking();
/**
@@ -143,11 +143,11 @@ private:
void PostProcessTest(cmCTestTestResult& res, int test);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
- ///! append MemoryTesterOutputFile to the test log
+ //! append MemoryTesterOutputFile to the test log
void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
std::string const& filename);
- ///! generate the output filename for the given test index
+ //! generate the output filename for the given test index
void TestOutputFileNames(int test, std::vector<std::string>& files);
};
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 756ac6cf6..ef63073b1 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -3,11 +3,13 @@
#include "cmCTestMultiProcessHandler.h"
#include "cmAffinity.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmListFileCache.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
@@ -108,8 +110,8 @@ void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load)
fake_load_value)) {
if (!cmSystemTools::StringToULong(fake_load_value.c_str(),
&this->FakeLoadForTesting)) {
- cmSystemTools::Error("Failed to parse fake load value: ",
- fake_load_value.c_str());
+ cmSystemTools::Error("Failed to parse fake load value: " +
+ fake_load_value);
}
}
}
@@ -651,16 +653,11 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList()
// Reverse iterate over the different dependency levels (deepest first).
// Sort tests within each level by COST and append them to the cost list.
- for (std::list<TestSet>::reverse_iterator i = priorityStack.rbegin();
- i != priorityStack.rend(); ++i) {
- TestSet const& currentSet = *i;
- TestComparator comp(this);
-
+ for (TestSet const& currentSet : cmReverseRange(priorityStack)) {
TestList sortedCopy;
-
- sortedCopy.insert(sortedCopy.end(), currentSet.begin(), currentSet.end());
-
- std::stable_sort(sortedCopy.begin(), sortedCopy.end(), comp);
+ cmAppend(sortedCopy, currentSet);
+ std::stable_sort(sortedCopy.begin(), sortedCopy.end(),
+ TestComparator(this));
for (auto const& j : sortedCopy) {
if (alreadySortedTests.find(j) == alreadySortedTests.end()) {
@@ -689,8 +686,8 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList()
presortedList.push_back(i.first);
}
- TestComparator comp(this);
- std::stable_sort(presortedList.begin(), presortedList.end(), comp);
+ std::stable_sort(presortedList.begin(), presortedList.end(),
+ TestComparator(this));
TestSet alreadySortedTests;
@@ -993,7 +990,7 @@ static Json::Value DumpCTestInfo(
const std::vector<std::string>& args = testRun.GetArguments();
if (!args.empty()) {
commandAndArgs.reserve(args.size() + 1);
- commandAndArgs.insert(commandAndArgs.end(), args.begin(), args.end());
+ cmAppend(commandAndArgs, args);
}
testInfo["command"] = DumpToJsonArray(commandAndArgs);
}
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 435be97b6..2eb8dba29 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -2,9 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestP4.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmsys/RegularExpression.hxx"
@@ -193,7 +195,7 @@ public:
{
this->SetLog(&P4->Log, prefix);
this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
- this->RegexDiff.compile("^\\.\\.\\. (.*)#[0-9]+ ([^ ]+)$");
+ this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)");
}
private:
@@ -323,10 +325,7 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
// The CTEST_P4_OPTIONS variable adds additional Perforce command line
// options before the main command
std::string opts = this->CTest->GetCTestConfiguration("P4Options");
- std::vector<std::string> args =
- cmSystemTools::ParseArguments(opts.c_str());
-
- P4Options.insert(P4Options.end(), args.begin(), args.end());
+ cmAppend(P4Options, cmSystemTools::ParseArguments(opts));
}
CommandOptions.clear();
@@ -425,12 +424,11 @@ bool cmCTestP4::LoadRevisions()
// p4 describe -s ...@1111111,2222222
std::vector<char const*> p4_describe;
- for (std::vector<std::string>::reverse_iterator i = ChangeLists.rbegin();
- i != ChangeLists.rend(); ++i) {
+ for (std::string const& i : cmReverseRange(ChangeLists)) {
SetP4Options(p4_describe);
p4_describe.push_back("describe");
p4_describe.push_back("-s");
- p4_describe.push_back(i->c_str());
+ p4_describe.push_back(i.c_str());
p4_describe.push_back(nullptr);
DescribeParser outDescribe(this, "p4_describe-out> ");
@@ -501,7 +499,7 @@ bool cmCTestP4::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
p4_sync.push_back(arg.c_str());
}
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 7f081ef89..31976b994 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -9,11 +9,10 @@
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
-#include "cm_zlib.h"
-#include "cmsys/Base64.h"
#include "cmsys/RegularExpression.hxx"
#include <chrono>
#include <cmAlgorithms.h>
+#include <cstdint>
#include <cstring>
#include <iomanip>
#include <ratio>
@@ -31,9 +30,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
this->TestResult.TestCount = 0;
this->TestResult.Properties = nullptr;
- this->ProcessOutput.clear();
- this->CompressedOutput.clear();
- this->CompressionRatio = 2;
this->NumberOfRunsLeft = 1; // default to 1 run of the test
this->RunUntilFail = false; // default to run the test once
this->RunAgain = false; // default to not having to run again
@@ -68,73 +64,8 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
}
}
-// Streamed compression of test output. The compressed data
-// is appended to this->CompressedOutput
-void cmCTestRunTest::CompressOutput()
-{
- int ret;
- z_stream strm;
-
- unsigned char* in = reinterpret_cast<unsigned char*>(
- const_cast<char*>(this->ProcessOutput.c_str()));
- // zlib makes the guarantee that this is the maximum output size
- int outSize = static_cast<int>(
- static_cast<double>(this->ProcessOutput.size()) * 1.001 + 13.0);
- unsigned char* out = new unsigned char[outSize];
-
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = deflateInit(&strm, -1); // default compression level
- if (ret != Z_OK) {
- delete[] out;
- return;
- }
-
- strm.avail_in = static_cast<uInt>(this->ProcessOutput.size());
- strm.next_in = in;
- strm.avail_out = outSize;
- strm.next_out = out;
- ret = deflate(&strm, Z_FINISH);
-
- if (ret != Z_STREAM_END) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error during output compression. Sending uncompressed output."
- << std::endl);
- delete[] out;
- return;
- }
-
- (void)deflateEnd(&strm);
-
- unsigned char* encoded_buffer =
- new unsigned char[static_cast<int>(outSize * 1.5)];
-
- size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
-
- this->CompressedOutput.clear();
- for (size_t i = 0; i < rlen; i++) {
- this->CompressedOutput += encoded_buffer[i];
- }
-
- if (strm.total_in) {
- this->CompressionRatio =
- static_cast<double>(strm.total_out) / static_cast<double>(strm.total_in);
- }
-
- delete[] encoded_buffer;
- delete[] out;
-}
-
bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
{
- if ((!this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressTestOutput()) ||
- (this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressTestOutput())) {
- this->CompressOutput();
- }
-
this->WriteLogOutputTop(completed, total);
std::string reason;
bool passed = true;
@@ -143,7 +74,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
if (res != cmProcess::State::Expired) {
this->TimeoutIsForStopTime = false;
}
- int retVal = this->TestProcess->GetExitValue();
+ std::int64_t retVal = this->TestProcess->GetExitValue();
bool forceFail = false;
bool skipped = false;
bool outputTestErrorsToConsole = false;
@@ -201,14 +132,17 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
} else {
this->TestResult.Status = cmCTestTestHandler::FAILED;
outputStream << "***Failed " << reason;
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
}
} else if (res == cmProcess::State::Expired) {
outputStream << "***Timeout ";
this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
} else if (res == cmProcess::State::Exception) {
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
outputStream << "***Exception: ";
this->TestResult.ExceptionStatus =
this->TestProcess->GetExitExceptionString();
@@ -335,10 +269,18 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
// if the test actually started and ran
// record the results in TestResult
if (started) {
- bool compress = !this->TestHandler->MemCheck &&
- this->CompressionRatio < 1 && this->CTest->ShouldCompressTestOutput();
+ std::string compressedOutput;
+ if (!this->TestHandler->MemCheck &&
+ this->CTest->ShouldCompressTestOutput()) {
+ std::string str = this->ProcessOutput;
+ if (this->CTest->CompressString(str)) {
+ compressedOutput = std::move(str);
+ }
+ }
+ bool compress = !compressedOutput.empty() &&
+ compressedOutput.length() < this->ProcessOutput.length();
this->TestResult.Output =
- compress ? this->CompressedOutput : this->ProcessOutput;
+ compress ? compressedOutput : this->ProcessOutput;
this->TestResult.CompressOutput = compress;
this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
if (!skipped) {
@@ -493,32 +435,26 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
this->ProcessOutput.clear();
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = cmDuration::zero();
+ this->TestResult.CompressOutput = false;
+ this->TestResult.ReturnValue = -1;
+ this->TestResult.TestCount = this->TestProperties->Index;
+ this->TestResult.Name = this->TestProperties->Name;
+ this->TestResult.Path = this->TestProperties->Directory;
+
// Return immediately if test is disabled
if (this->TestProperties->Disabled) {
- this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = cmDuration::zero();
- this->TestResult.CompressOutput = false;
- this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Disabled";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
- this->TestResult.TestCount = this->TestProperties->Index;
- this->TestResult.Name = this->TestProperties->Name;
- this->TestResult.Path = this->TestProperties->Directory;
this->TestProcess = cm::make_unique<cmProcess>(*this);
this->TestResult.Output = "Disabled";
this->TestResult.FullCommandLine.clear();
return false;
}
- this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = cmDuration::zero();
- this->TestResult.CompressOutput = false;
- this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Failed to start";
this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND;
- this->TestResult.TestCount = this->TestProperties->Index;
- this->TestResult.Name = this->TestProperties->Name;
- this->TestResult.Path = this->TestProperties->Directory;
// Check for failed fixture dependencies before we even look at the command
// arguments because if we are not going to run the test, the command and
@@ -696,9 +632,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
{
this->TestProcess = cm::make_unique<cmProcess>(*this);
this->TestProcess->SetId(this->Index);
- this->TestProcess->SetWorkingDirectory(
- this->TestProperties->Directory.c_str());
- this->TestProcess->SetCommand(this->ActualCommand.c_str());
+ this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
+ this->TestProcess->SetCommand(this->ActualCommand);
this->TestProcess->SetCommandArguments(this->Arguments);
// determine how much time we have
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 918d5fa58..38cc417e5 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -58,9 +58,6 @@ public:
// Read and store output. Returns true if it must be called again.
void CheckOutput(std::string const& line);
- // Compresses the output, writing to CompressedOutput
- void CompressOutput();
-
// launch the test process, return whether it started correctly
bool StartTest(size_t completed, size_t total);
// capture and report the test results
@@ -105,8 +102,6 @@ private:
cmCTest* CTest;
std::unique_ptr<cmProcess> TestProcess;
std::string ProcessOutput;
- std::string CompressedOutput;
- double CompressionRatio;
// The test results
cmCTestTestHandler::cmCTestTestResult TestResult;
cmCTestMultiProcessHandler& MultiTestHandler;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 3bf66ca23..c834686d7 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSVN.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -242,7 +243,7 @@ bool cmCTestSVN::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// Specify the start time for nightly testing.
if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
@@ -269,15 +270,13 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
std::vector<char const*> args;
args.push_back(this->CommandLineTool.c_str());
-
- args.insert(args.end(), parameters.begin(), parameters.end());
-
+ cmAppend(args, parameters);
args.push_back("--non-interactive");
std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
std::vector<std::string> parsedUserOptions =
- cmSystemTools::ParseArguments(userOptions.c_str());
+ cmSystemTools::ParseArguments(userOptions);
for (std::string const& opt : parsedUserOptions) {
args.push_back(opt.c_str());
}
@@ -344,7 +343,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
@@ -515,7 +514,7 @@ private:
if (path.size() > this->SVN->SourceDirectory.size() &&
strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
this->SVN->SourceDirectory.size()) == 0) {
- local_path = path.c_str() + this->SVN->SourceDirectory.size() + 1;
+ local_path = path.substr(this->SVN->SourceDirectory.size() + 1);
} else {
local_path = path;
}
@@ -554,7 +553,7 @@ std::string cmCTestSVN::SVNInfo::BuildLocalPath(std::string const& path) const
// Add path with base prefix removed
if (path.size() > this->Base.size() &&
strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0) {
- local_path += (path.c_str() + this->Base.size());
+ local_path += path.substr(this->Base.size());
} else {
local_path += path;
}
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 33b8b4a4c..a739f440c 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -199,7 +199,7 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
// cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
// cmsysProcess_SetTimeout(cp, timeout);
@@ -288,11 +288,12 @@ void cmCTestScriptHandler::CreateCMake()
this->ParentMakefile->GetRecursionDepth());
}
- this->CMake->SetProgressCallback([this](const char* m, float /*unused*/) {
- if (m && *m) {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
- }
- });
+ this->CMake->SetProgressCallback(
+ [this](const std::string& m, float /*unused*/) {
+ if (!m.empty()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
+ }
+ });
this->AddCTestCommand("ctest_build", new cmCTestBuildCommand);
this->AddCTestCommand("ctest_configure", new cmCTestConfigureCommand);
@@ -330,7 +331,7 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
}
// make sure the file exists
if (!cmSystemTools::FileExists(script)) {
- cmSystemTools::Error("Cannot find file: ", script.c_str());
+ cmSystemTools::Error("Cannot find file: " + script);
return 1;
}
@@ -446,7 +447,8 @@ int cmCTestScriptHandler::ExtractVariables()
if (updateVal) {
if (this->UpdateCmd.empty()) {
cmSystemTools::Error(
- updateVar, " specified without specifying CTEST_CVS_COMMAND.");
+ std::string(updateVar) +
+ " specified without specifying CTEST_CVS_COMMAND.");
return 12;
}
this->ExtraUpdates.emplace_back(updateVal);
@@ -470,8 +472,8 @@ int cmCTestScriptHandler::ExtractVariables()
msg += "\nCTEST_COMMAND = ";
msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
cmSystemTools::Error(
- "Some required settings in the configuration file were missing:\n",
- msg.c_str());
+ "Some required settings in the configuration file were missing:\n" +
+ msg);
return 4;
}
@@ -607,12 +609,10 @@ int cmCTestScriptHandler::CheckOutSourceDir()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run cvs: " << this->CVSCheckOut << std::endl);
res = cmSystemTools::RunSingleCommand(
- this->CVSCheckOut.c_str(), &output, &output, &retVal,
- this->CTestRoot.c_str(), this->HandlerVerbose,
- cmDuration::zero() /*this->TimeOut*/);
+ this->CVSCheckOut, &output, &output, &retVal, this->CTestRoot.c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!res || retVal != 0) {
- cmSystemTools::Error("Unable to perform cvs checkout:\n",
- output.c_str());
+ cmSystemTools::Error("Unable to perform cvs checkout:\n" + output);
return 6;
}
}
@@ -675,11 +675,11 @@ int cmCTestScriptHandler::PerformExtraUpdates()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run Update: " << fullCommand << std::endl);
res = cmSystemTools::RunSingleCommand(
- fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
+ fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!res || retVal != 0) {
- cmSystemTools::Error("Unable to perform extra updates:\n", eu.c_str(),
- "\nWith output:\n", output.c_str());
+ cmSystemTools::Error("Unable to perform extra updates:\n" + eu +
+ "\nWith output:\n" + output);
return 0;
}
}
@@ -721,8 +721,8 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
if (!cmSystemTools::FileExists(this->BinaryDir) &&
this->SourceDir != this->BinaryDir) {
if (!cmSystemTools::MakeDirectory(this->BinaryDir)) {
- cmSystemTools::Error("Unable to create the binary directory:\n",
- this->BinaryDir.c_str());
+ cmSystemTools::Error("Unable to create the binary directory:\n" +
+ this->BinaryDir);
this->RestoreBackupDirectories();
return 7;
}
@@ -779,7 +779,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run cmake command: " << command << std::endl);
res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!this->CMOutFile.empty()) {
@@ -818,7 +818,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run ctest command: " << command << std::endl);
res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
// did something critical fail in ctest
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 00c061016..afc3e67d9 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -3,7 +3,6 @@
#include "cmCTestSubmitCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestSubmitHandler.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -13,6 +12,29 @@
class cmExecutionStatus;
+cmCTestSubmitCommand::cmCTestSubmitCommand()
+{
+ this->PartsMentioned = false;
+ this->FilesMentioned = false;
+ this->InternalTest = false;
+ this->RetryCount = "";
+ this->RetryDelay = "";
+ this->CDashUpload = false;
+ this->Arguments[cts_BUILD_ID] = "BUILD_ID";
+ this->Last = cts_LAST;
+}
+
+/**
+ * This is a virtual constructor for the command.
+ */
+cmCommand* cmCTestSubmitCommand::Clone()
+{
+ cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+}
+
cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
{
const char* submitURL = !this->SubmitURL.empty()
@@ -42,33 +64,23 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
this->Makefile->GetDefinition("CTEST_NOTES_FILES");
if (notesFilesVariable) {
std::vector<std::string> notesFiles;
- cmCTest::VectorOfStrings newNotesFiles;
cmSystemTools::ExpandListArgument(notesFilesVariable, notesFiles);
- newNotesFiles.insert(newNotesFiles.end(), notesFiles.begin(),
- notesFiles.end());
- this->CTest->GenerateNotesFile(newNotesFiles);
+ this->CTest->GenerateNotesFile(notesFiles);
}
const char* extraFilesVariable =
this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
if (extraFilesVariable) {
std::vector<std::string> extraFiles;
- cmCTest::VectorOfStrings newExtraFiles;
cmSystemTools::ExpandListArgument(extraFilesVariable, extraFiles);
- newExtraFiles.insert(newExtraFiles.end(), extraFiles.begin(),
- extraFiles.end());
- if (!this->CTest->SubmitExtraFiles(newExtraFiles)) {
+ if (!this->CTest->SubmitExtraFiles(extraFiles)) {
this->SetError("problem submitting extra files.");
return nullptr;
}
}
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("submit");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate submit handler");
- return nullptr;
- }
+ cmCTestSubmitHandler* handler = this->CTest->GetSubmitHandler();
+ handler->Initialize();
// If no FILES or PARTS given, *all* PARTS are submitted by default.
//
@@ -90,38 +102,30 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// But FILES with no PARTS mentioned should just submit the FILES
// without any of the default parts.
//
- std::set<cmCTest::Part> noParts;
- static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(noParts);
-
- static_cast<cmCTestSubmitHandler*>(handler)->SelectFiles(this->Files);
+ handler->SelectParts(std::set<cmCTest::Part>());
+ handler->SelectFiles(this->Files);
}
// If a PARTS option was given, select only the named parts for submission.
//
if (this->PartsMentioned) {
- static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts);
+ handler->SelectParts(this->Parts);
}
// Pass along any HTTPHEADER to the handler if this option was given.
if (!this->HttpHeaders.empty()) {
- static_cast<cmCTestSubmitHandler*>(handler)->SetHttpHeaders(
- this->HttpHeaders);
+ handler->SetHttpHeaders(this->HttpHeaders);
}
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "RetryDelay", this->RetryDelay.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "RetryCount", this->RetryCount.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "InternalTest", this->InternalTest ? "ON" : "OFF");
+ handler->SetOption("RetryDelay", this->RetryDelay.c_str());
+ handler->SetOption("RetryCount", this->RetryCount.c_str());
+ handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
handler->SetQuiet(this->Quiet);
if (this->CDashUpload) {
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "CDashUploadFile", this->CDashUploadFile.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "CDashUploadType", this->CDashUploadType.c_str());
+ handler->SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+ handler->SetOption("CDashUploadType", this->CDashUploadType.c_str());
}
return handler;
}
@@ -130,7 +134,15 @@ bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
- return this->cmCTestHandlerCommand::InitialPass(args, status);
+
+ bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
+
+ if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) {
+ this->Makefile->AddDefinition(this->Values[cts_BUILD_ID],
+ this->CTest->GetBuildID().c_str());
+ }
+
+ return ret;
}
bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 0caccd66d..1e270466d 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -25,26 +25,8 @@ class cmExecutionStatus;
class cmCTestSubmitCommand : public cmCTestHandlerCommand
{
public:
- cmCTestSubmitCommand()
- {
- this->PartsMentioned = false;
- this->FilesMentioned = false;
- this->InternalTest = false;
- this->RetryCount = "";
- this->RetryDelay = "";
- this->CDashUpload = false;
- }
-
- /**
- * This is a virtual constructor for the command.
- */
- cmCommand* Clone() override
- {
- cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return ni;
- }
+ cmCTestSubmitCommand();
+ cmCommand* Clone() override;
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) override;
@@ -75,11 +57,17 @@ protected:
ArgumentDoingLast2
};
+ enum
+ {
+ cts_BUILD_ID = ct_LAST,
+ cts_LAST
+ };
+
bool PartsMentioned;
std::set<cmCTest::Part> Parts;
bool FilesMentioned;
bool InternalTest;
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
std::string RetryCount;
std::string RetryDelay;
bool CDashUpload;
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 87112da9e..1fa7988b7 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -63,7 +63,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CurrentValue.insert(this->CurrentValue.end(), data, data + length);
+ cmAppend(this->CurrentValue, data, data + length);
}
void EndElement(const std::string& name) override
@@ -93,12 +93,9 @@ static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
size_t nmemb, void* data)
{
int realsize = static_cast<int>(size * nmemb);
-
- cmCTestSubmitHandlerVectorOfChar* vec =
- static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
-
+ cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
return realsize;
}
@@ -107,10 +104,8 @@ static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/,
char* chPtr, size_t size,
void* data)
{
- cmCTestSubmitHandlerVectorOfChar* vec =
- static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
- vec->insert(vec->end(), chPtr, chPtr + size);
-
+ cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + size);
return size;
}
@@ -259,8 +254,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag());
upload_as += "-";
upload_as += ctest_curl.Escape(this->CTest->GetTestModelString());
- cmCTestScriptHandler* ch = static_cast<cmCTestScriptHandler*>(
- this->CTest->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
cmake* cm = ch->GetCMake();
if (cm) {
const char* subproject =
@@ -343,7 +337,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
if (!chunk.empty()) {
cmCTestOptionalLog(this->CTest, DEBUG,
"CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << cmCTestLogWrite(chunk.data(), chunk.size())
<< "]" << std::endl,
this->Quiet);
this->ParseResponse(chunk);
@@ -352,7 +346,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
cmCTestOptionalLog(
this->CTest, DEBUG,
"CURL debug output: ["
- << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << cmCTestLogWrite(chunkDebug.data(), chunkDebug.size()) << "]"
<< std::endl,
this->Quiet);
}
@@ -404,12 +398,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
res = ::curl_easy_perform(curl);
if (!chunk.empty()) {
- cmCTestOptionalLog(
- this->CTest, DEBUG,
- "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl,
- this->Quiet);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "CURL output: ["
+ << cmCTestLogWrite(chunk.data(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
this->ParseResponse(chunk);
}
@@ -433,11 +426,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
// avoid deref of begin for zero size array
if (!chunk.empty()) {
*this->LogFile << " Curl output was: "
- << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << cmCTestLogWrite(chunk.data(), chunk.size())
<< std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE,
"CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "]"
<< std::endl);
}
::curl_easy_cleanup(curl);
@@ -486,7 +479,7 @@ void cmCTestSubmitHandler::ParseResponse(
if (this->HasWarnings || this->HasErrors) {
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Server Response:\n"
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "\n");
}
}
@@ -559,8 +552,7 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
// has already been uploaded
// TODO I added support for subproject. You would need to add
// a "&subproject=subprojectname" to the first POST.
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
cmake* cm = ch->GetCMake();
const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
// TODO: Encode values for a URL instead of trusting caller.
@@ -772,8 +764,7 @@ int cmCTestSubmitHandler::ProcessHandler()
if (!this->Files.empty()) {
// Submit the explicitly selected files:
- //
- files.insert(files.end(), this->Files.begin(), this->Files.end());
+ cmAppend(files, this->Files);
}
// Add to the list of files to submit from any selected, existing parts:
@@ -819,8 +810,7 @@ int cmCTestSubmitHandler::ProcessHandler()
}
// Submit files from this part.
- std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
- files.insert(files.end(), pfiles.begin(), pfiles.end());
+ cmAppend(files, this->CTest->GetSubmitFiles(p));
}
// Make sure files are unique, but preserve order.
@@ -903,7 +893,7 @@ void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
}
}
-void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
+void cmCTestSubmitHandler::SelectFiles(std::set<std::string> const& files)
{
this->Files.insert(files.begin(), files.end());
}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index 58f4f975d..e0fed10e0 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -38,7 +38,7 @@ public:
void SelectParts(std::set<cmCTest::Part> const& parts);
/** Specify a set of files to submit. */
- void SelectFiles(cmCTest::SetOfStrings const& files);
+ void SelectFiles(std::set<std::string> const& files);
// handle the cdash file upload protocol
int HandleCDashUploadFile(std::string const& file, std::string const& type);
@@ -74,7 +74,7 @@ private:
bool SubmitPart[cmCTest::PartCount];
bool HasWarnings;
bool HasErrors;
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
std::vector<std::string> HttpHeaders;
};
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 895ca1267..cfd5e3dd2 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -4,6 +4,7 @@
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -140,5 +141,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
{
- return this->CTest->GetInitializedHandler("test");
+ cmCTestTestHandler* handler = this->CTest->GetTestHandler();
+ handler->Initialize();
+ return handler;
}
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index cf2652afe..0ed56c850 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1486,7 +1486,7 @@ int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec)
int retVal = 0;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run command: " << it << std::endl, this->Quiet);
- if (!cmSystemTools::RunSingleCommand(it.c_str(), nullptr, nullptr, &retVal,
+ if (!cmSystemTools::RunSingleCommand(it, nullptr, nullptr, &retVal,
nullptr, cmSystemTools::OUTPUT_MERGE
/*this->Verbose*/) ||
retVal != 0) {
@@ -2265,8 +2265,8 @@ bool cmCTestTestHandler::SetTestsProperties(
size_t pos = val.find_first_of('=');
if (pos != std::string::npos) {
std::string mKey = val.substr(0, pos);
- const char* mVal = val.c_str() + pos + 1;
- rt.Measurements[mKey] = mVal;
+ std::string mVal = val.substr(pos + 1);
+ rt.Measurements[mKey] = std::move(mVal);
} else {
rt.Measurements[val] = "1";
}
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 0b557dbcb..7f3f5e4f8 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -11,6 +11,7 @@
#include "cmsys/RegularExpression.hxx"
#include <chrono>
+#include <cstdint>
#include <iosfwd>
#include <map>
#include <set>
@@ -58,7 +59,7 @@ public:
*/
void PopulateCustomVectors(cmMakefile* mf) override;
- ///! Control the use of the regular expresisons, call these methods to turn
+ //! Control the use of the regular expresisons, call these methods to turn
/// them on
void UseIncludeRegExp();
void UseExcludeRegExp();
@@ -77,7 +78,7 @@ public:
this->CustomMaximumFailedTestOutputSize = n;
}
- ///! pass the -I argument down
+ //! pass the -I argument down
void SetTestsToRunInformation(const char*);
cmCTestTestHandler();
@@ -153,7 +154,7 @@ public:
std::string Reason;
std::string FullCommandLine;
cmDuration ExecutionTime;
- int ReturnValue;
+ std::int64_t ReturnValue;
int Status;
std::string ExceptionStatus;
bool CompressOutput;
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 3d800f8b3..65dc9211a 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -3,7 +3,7 @@
#include "cmCTestUpdateCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestUpdateHandler.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -62,6 +62,9 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOverride", "CTEST_UPDATE_VERSION_OVERRIDE",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "HGCommand", "CTEST_HG_COMMAND", this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", this->Quiet);
@@ -74,12 +77,8 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("update");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate update handler");
- return nullptr;
- }
+ cmCTestUpdateHandler* handler = this->CTest->GetUpdateHandler();
+ handler->Initialize();
handler->SetCommand(this);
if (source_dir.empty()) {
this->SetError("source directory not specified. Please use SOURCE tag");
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index e3b7e9ef3..5cfc4a7cd 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -199,6 +199,10 @@ int cmCTestUpdateHandler::ProcessHandler()
xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
xml.Element("UpdateType",
cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+ std::string changeId = this->CTest->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Element("ChangeId", changeId);
+ }
bool loadedMods = vc->WriteXML(xml);
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 2fe2cd347..59fbf371c 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -6,7 +6,6 @@
#include <vector>
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestUploadHandler.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -14,14 +13,9 @@
cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("upload");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate upload handler");
- return nullptr;
- }
- static_cast<cmCTestUploadHandler*>(handler)->SetFiles(this->Files);
-
+ cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
+ handler->Initialize();
+ handler->SetFiles(this->Files);
handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index 61bf1cc58..0d3b06e43 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -5,9 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmCTest.h"
#include "cmCTestHandlerCommand.h"
+#include <set>
#include <string>
class cmCTestGenericHandler;
@@ -22,8 +22,6 @@ class cmCommand;
class cmCTestUploadCommand : public cmCTestHandlerCommand
{
public:
- cmCTestUploadCommand() {}
-
/**
* This is a virtual constructor for the command.
*/
@@ -55,7 +53,7 @@ protected:
ArgumentDoingLast2
};
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
};
#endif
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
index 261ecab9a..9efdf70b8 100644
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUploadHandler.h"
+#include "cmCTest.h"
#include "cmGeneratedFileStream.h"
#include "cmVersion.h"
#include "cmXMLWriter.h"
@@ -20,7 +21,7 @@ void cmCTestUploadHandler::Initialize()
this->Files.clear();
}
-void cmCTestUploadHandler::SetFiles(const cmCTest::SetOfStrings& files)
+void cmCTestUploadHandler::SetFiles(std::set<std::string> const& files)
{
this->Files = files;
}
@@ -50,7 +51,7 @@ int cmCTestUploadHandler::ProcessHandler()
this->CTest->GetTestModelString());
xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->CTest->AddSiteProperties(xml);
xml.StartElement("Upload");
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
index ff5057418..4d8fab487 100644
--- a/Source/CTest/cmCTestUploadHandler.h
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -5,9 +5,11 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include <set>
+#include <string>
+
/** \class cmCTestUploadHandler
* \brief Helper class for CTest
*
@@ -20,7 +22,6 @@ public:
typedef cmCTestGenericHandler Superclass;
cmCTestUploadHandler();
- ~cmCTestUploadHandler() override {}
/*
* The main entry point for this class
@@ -30,10 +31,10 @@ public:
void Initialize() override;
/** Specify a set of files to submit. */
- void SetFiles(cmCTest::SetOfStrings const& files);
+ void SetFiles(std::set<std::string> const& files);
private:
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
};
#endif
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index 374e73ffb..eea41cf74 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -141,6 +141,15 @@ void cmCTestVC::CleanupImpl()
bool cmCTestVC::Update()
{
bool result = true;
+
+ // Use the explicitly specified version.
+ std::string versionOverride =
+ this->CTest->GetCTestConfiguration("UpdateVersionOverride");
+ if (!versionOverride.empty()) {
+ this->SetNewRevision(versionOverride);
+ return true;
+ }
+
// if update version only is on then do not actually update,
// just note the current version and finish
if (!cmSystemTools::IsOn(
@@ -166,6 +175,11 @@ bool cmCTestVC::NoteNewRevision()
return true;
}
+void cmCTestVC::SetNewRevision(std::string const& /*unused*/)
+{
+ // We do nothing by default.
+}
+
bool cmCTestVC::UpdateImpl()
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index 69a3bf023..2a4765d28 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -70,6 +70,7 @@ protected:
virtual bool NoteOldRevision();
virtual bool UpdateImpl();
virtual bool NoteNewRevision();
+ virtual void SetNewRevision(std::string const& revision);
virtual bool WriteXMLUpdates(cmXMLWriter& xml);
#if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x510
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 70ef8dfcd..7a3b82e61 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -2,62 +2,23 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmProcess.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
+#include "cmGetPipes.h"
#include "cmsys/Process.h"
-#include <fcntl.h>
#include <iostream>
#include <signal.h>
#include <string>
-#if !defined(_WIN32)
-# include <unistd.h>
+#if defined(_WIN32)
+# include "cm_kwiml.h"
#endif
#include <utility>
#define CM_PROCESS_BUF_SIZE 65536
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <io.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- SECURITY_ATTRIBUTES attr;
- HANDLE readh, writeh;
- attr.nLength = sizeof(attr);
- attr.lpSecurityDescriptor = nullptr;
- attr.bInheritHandle = FALSE;
- if (!CreatePipe(&readh, &writeh, &attr, 0))
- return uv_translate_sys_error(GetLastError());
- fds[0] = _open_osfhandle((intptr_t)readh, 0);
- fds[1] = _open_osfhandle((intptr_t)writeh, 0);
- if (fds[0] == -1 || fds[1] == -1) {
- CloseHandle(readh);
- CloseHandle(writeh);
- return uv_translate_sys_error(GetLastError());
- }
- return 0;
-}
-#else
-# include <errno.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- if (pipe(fds) == -1) {
- return uv_translate_sys_error(errno);
- }
-
- if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
- fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
- close(fds[0]);
- close(fds[1]);
- return uv_translate_sys_error(errno);
- }
- return 0;
-}
-#endif
-
cmProcess::cmProcess(cmCTestRunTest& runner)
: Runner(runner)
, Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
@@ -71,7 +32,7 @@ cmProcess::cmProcess(cmCTestRunTest& runner)
cmProcess::~cmProcess() = default;
-void cmProcess::SetCommand(const char* command)
+void cmProcess::SetCommand(std::string const& command)
{
this->Command = command;
}
@@ -81,6 +42,11 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
this->Arguments = args;
}
+void cmProcess::SetWorkingDirectory(std::string const& dir)
+{
+ this->WorkingDirectory = dir;
+}
+
bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
{
this->ProcessState = cmProcess::State::Error;
@@ -113,7 +79,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
pipe_reader.init(loop, 0, this);
int fds[2] = { -1, -1 };
- status = cmProcessGetPipes(fds);
+ status = cmGetPipes(fds);
if (status != 0) {
cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
"Error initializing pipe: " << uv_strerror(status)
@@ -199,7 +165,7 @@ bool cmProcess::Buffer::GetLine(std::string& line)
for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
// Extract the range first..last as a line.
- const char* text = &*this->begin() + this->First;
+ const char* text = this->data() + this->First;
size_type length = this->Last - this->First;
while (length && text[length - 1] == '\r') {
length--;
@@ -229,7 +195,7 @@ bool cmProcess::Buffer::GetLast(std::string& line)
{
// Return the partial last line, if any.
if (!this->empty()) {
- line.assign(&*this->begin(), this->size());
+ line.assign(this->data(), this->size());
this->First = this->Last = 0;
this->clear();
return true;
@@ -250,7 +216,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
if (nread > 0) {
std::string strdata;
this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
- this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+ cmAppend(this->Output, strdata);
while (this->Output.GetLine(line)) {
this->Runner.CheckOutput(line);
@@ -353,7 +319,7 @@ void cmProcess::OnExit(int64_t exit_status, int term_signal)
}
// Record exit information.
- this->ExitValue = static_cast<int>(exit_status);
+ this->ExitValue = exit_status;
this->Signal = term_signal;
this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
// Because of a processor clock scew the runtime may become slightly
@@ -539,7 +505,8 @@ std::string cmProcess::GetExitExceptionString()
case STATUS_NO_MEMORY:
default:
char buf[1024];
- _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
+ const char* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n";
+ _snprintf(buf, 1024, fmt, this->ExitValue);
exception_str.assign(buf);
}
#else
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index b2d87fab3..a0a4b6b20 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -28,10 +28,9 @@ class cmProcess
public:
explicit cmProcess(cmCTestRunTest& runner);
~cmProcess();
- const char* GetCommand() { return this->Command.c_str(); }
- void SetCommand(const char* command);
+ void SetCommand(std::string const& command);
void SetCommandArguments(std::vector<std::string> const& arg);
- void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetWorkingDirectory(std::string const& dir);
void SetTimeout(cmDuration t) { this->Timeout = t; }
void ChangeTimeout(cmDuration t);
void ResetStartTime();
@@ -53,7 +52,7 @@ public:
State GetProcessStatus();
int GetId() { return this->Id; }
void SetId(int id) { this->Id = id; }
- int GetExitValue() { return this->ExitValue; }
+ int64_t GetExitValue() { return this->ExitValue; }
cmDuration GetTotalTime() { return this->TotalTime; }
enum class Exception
@@ -122,7 +121,7 @@ private:
std::vector<std::string> Arguments;
std::vector<const char*> ProcessArgs;
int Id;
- int ExitValue;
+ int64_t ExitValue;
};
#endif
diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp
index 9ea52c456..593d9b263 100644
--- a/Source/Checks/cm_cxx17_check.cpp
+++ b/Source/Checks/cm_cxx17_check.cpp
@@ -3,6 +3,10 @@
#include <memory>
#include <unordered_map>
+#ifdef _MSC_VER
+# include <comdef.h>
+#endif
+
int main()
{
int a[] = { 0, 1, 2 };
@@ -14,5 +18,14 @@ int main()
auto ci = std::size(a);
std::unique_ptr<int> u(new int(0));
+
+#ifdef _MSC_VER
+ // clang-cl has problems instantiating this constructor in C++17 mode
+ // error: indirection requires pointer operand ('const _GUID' invalid)
+ // return *_IID;
+ IUnknownPtr ptr{};
+ IDispatchPtr disp(ptr);
+#endif
+
return *u + *ai + *(bi - 1) + (3 - static_cast<int>(ci));
}
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index f2982a62c..7caed0cd5 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -67,6 +67,7 @@ void onsig(int /*unused*/)
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
cmsys::Encoding::CommandLineArguments encoding_args =
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
argc = encoding_args.argc();
@@ -150,7 +151,7 @@ int main(int argc, char const* const* argv)
}
cmSystemTools::SetMessageCallback(
- [myform](const char* message, const char* title) {
+ [myform](const std::string& message, const char* title) {
myform->AddError(message, title);
});
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
index e7ed09717..c1dd591e0 100644
--- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -83,7 +83,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
break;
}
case cmStateEnums::UNINITIALIZED:
- cmSystemTools::Error("Found an undefined variable: ", key.c_str());
+ cmSystemTools::Error("Found an undefined variable: " + key);
break;
default:
// TODO : put warning message here
diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h
index ddb67deeb..78429059e 100644
--- a/Source/CursesDialog/cmCursesForm.h
+++ b/Source/CursesDialog/cmCursesForm.h
@@ -9,6 +9,8 @@
#include "cmsys/FStream.hxx"
+#include <string>
+
class cmCursesForm
{
public:
@@ -34,7 +36,7 @@ public:
// Description:
// During a CMake run, an error handle should add errors
// to be displayed afterwards.
- virtual void AddError(const char*, const char*) {}
+ virtual void AddError(const std::string&, const char*) {}
// Description:
// Turn debugging on. This will create ccmakelog.txt.
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index a41d051b1..4e887d68f 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -19,9 +19,8 @@ cmCursesLongMessageForm::cmCursesLongMessageForm(
std::vector<std::string> const& messages, const char* title)
{
// Append all messages into on big string
- std::vector<std::string>::const_iterator it;
- for (it = messages.begin(); it != messages.end(); it++) {
- this->Messages += (*it);
+ for (std::string const& message : messages) {
+ this->Messages += message;
// Add one blank line after each message
this->Messages += "\n\n";
}
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 8ca7802f1..028e85298 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -79,18 +79,11 @@ cmCursesMainForm::~cmCursesMainForm()
// See if a cache entry is in the list of entries in the ui.
bool cmCursesMainForm::LookForCacheEntry(const std::string& key)
{
- if (!this->Entries) {
- return false;
- }
-
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
- if (key == (*it)->Key) {
- return true;
- }
- }
-
- return false;
+ return this->Entries &&
+ std::any_of(this->Entries->begin(), this->Entries->end(),
+ [&key](cmCursesCacheEntryComposite* entry) {
+ return key == entry->Key;
+ });
}
// Create new cmCursesCacheEntryComposite entries from the cache
@@ -107,10 +100,9 @@ void cmCursesMainForm::InitializeUI()
// Count non-internal and non-static entries
int count = 0;
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
t != cmStateEnums::UNINITIALIZED) {
++count;
@@ -130,11 +122,9 @@ void cmCursesMainForm::InitializeUI()
// Create the composites.
// First add entries which are new
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- std::string key = *it;
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
@@ -148,11 +138,9 @@ void cmCursesMainForm::InitializeUI()
}
// then add entries which are old
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- std::string key = *it;
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
@@ -190,13 +178,12 @@ void cmCursesMainForm::RePost()
} else {
// If normal mode, count only non-advanced entries
this->NumberOfVisibleEntries = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -217,27 +204,26 @@ void cmCursesMainForm::RePost()
// Assign fields
int j = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
- this->Fields[3 * j] = (*it)->Label->Field;
- this->Fields[3 * j + 1] = (*it)->IsNewLabel->Field;
- this->Fields[3 * j + 2] = (*it)->Entry->Field;
+ this->Fields[3 * j] = entry->Label->Field;
+ this->Fields[3 * j + 1] = entry->IsNewLabel->Field;
+ this->Fields[3 * j + 2] = entry->Entry->Field;
j++;
}
// if no cache entries there should still be one dummy field
if (j == 0) {
- it = this->Entries->begin();
- this->Fields[0] = (*it)->Label->Field;
- this->Fields[1] = (*it)->IsNewLabel->Field;
- this->Fields[2] = (*it)->Entry->Field;
+ const auto& front = *this->Entries->front();
+ this->Fields[0] = front.Label->Field;
+ this->Fields[1] = front.IsNewLabel->Field;
+ this->Fields[2] = front.Entry->Field;
this->NumberOfVisibleEntries = 1;
}
// Has to be null terminated.
@@ -278,13 +264,12 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
} else {
// If normal, display only non-advanced entries
this->NumberOfVisibleEntries = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -297,13 +282,12 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
if (height > 0) {
bool isNewPage;
int i = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -314,10 +298,10 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
if (isNewPage) {
this->NumberOfPages++;
}
- (*it)->Label->Move(left, top + row - 1, isNewPage);
- (*it)->IsNewLabel->Move(left + 32, top + row - 1, false);
- (*it)->Entry->Move(left + 33, top + row - 1, false);
- (*it)->Entry->SetPage(this->NumberOfPages);
+ entry->Label->Move(left, top + row - 1, isNewPage);
+ entry->IsNewLabel->Move(left + 32, top + row - 1, false);
+ entry->Entry->Move(left + 33, top + row - 1, false);
+ entry->Entry->SetPage(this->NumberOfPages);
i++;
}
}
@@ -506,14 +490,14 @@ void cmCursesMainForm::UpdateStatusBar(const char* message)
pos_form_cursor(this->Form);
}
-void cmCursesMainForm::UpdateProgress(const char* msg, float prog)
+void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
{
char tmp[1024];
const char* cmsg = tmp;
if (prog >= 0) {
- sprintf(tmp, "%s %i%%", msg, static_cast<int>(100 * prog));
+ sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
} else {
- cmsg = msg;
+ cmsg = msg.c_str();
}
this->UpdateStatusBar(cmsg);
this->PrintKeys(1);
@@ -533,7 +517,9 @@ int cmCursesMainForm::Configure(int noconfigure)
touchwin(stdscr);
refresh();
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
// always save the current gui values to disk
this->FillCacheManagerFromUI();
@@ -603,7 +589,9 @@ int cmCursesMainForm::Generate()
touchwin(stdscr);
refresh();
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
// Get rid of previous errors
this->Errors = std::vector<std::string>();
@@ -647,7 +635,8 @@ int cmCursesMainForm::Generate()
return 0;
}
-void cmCursesMainForm::AddError(const char* message, const char* /*unused*/)
+void cmCursesMainForm::AddError(const std::string& message,
+ const char* /*unused*/)
{
this->Errors.emplace_back(message);
}
@@ -658,28 +647,29 @@ void cmCursesMainForm::RemoveEntry(const char* value)
return;
}
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
- const char* val = (*it)->GetValue();
- if (val && !strcmp(value, val)) {
- this->CMakeInstance->UnwatchUnusedCli(value);
- this->Entries->erase(it);
- break;
- }
+ auto removeIt =
+ std::find_if(this->Entries->begin(), this->Entries->end(),
+ [value](cmCursesCacheEntryComposite* entry) -> bool {
+ const char* val = entry->GetValue();
+ return val != nullptr && !strcmp(value, val);
+ });
+
+ if (removeIt != this->Entries->end()) {
+ this->CMakeInstance->UnwatchUnusedCli(value);
+ this->Entries->erase(removeIt);
}
}
// copy from the list box to the cache manager
void cmCursesMainForm::FillCacheManagerFromUI()
{
- size_t size = this->Entries->size();
- for (size_t i = 0; i < size; i++) {
- std::string cacheKey = (*this->Entries)[i]->Key;
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
+ const std::string& cacheKey = entry->Key;
const char* existingValue =
this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
if (existingValue) {
std::string oldValue = existingValue;
- std::string newValue = (*this->Entries)[i]->Entry->GetValue();
+ std::string newValue = entry->Entry->GetValue();
std::string fixedOldValue;
std::string fixedNewValue;
cmStateEnums::CacheEntryType t =
@@ -975,17 +965,14 @@ void cmCursesMainForm::HandleInput()
if (nextCur) {
// make the next or prev. current field after deletion
- nextCur = nullptr;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end();
- ++it) {
- if (nextVal == (*it)->Key) {
- nextCur = (*it)->Entry->Field;
- }
- }
-
- if (nextCur) {
- set_current_field(this->Form, nextCur);
+ auto nextEntryIt =
+ std::find_if(this->Entries->begin(), this->Entries->end(),
+ [&nextVal](cmCursesCacheEntryComposite* entry) {
+ return nextVal == entry->Key;
+ });
+
+ if (nextEntryIt != this->Entries->end()) {
+ set_current_field(this->Form, (*nextEntryIt)->Entry->Field);
}
}
}
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index cc6482fd3..d37997581 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -81,7 +81,7 @@ public:
* During a CMake run, an error handle should add errors
* to be displayed afterwards.
*/
- void AddError(const char* message, const char* title) override;
+ void AddError(const std::string& message, const char* title) override;
/**
* Used to do a configure. If argument is specified, it does only the check
@@ -102,7 +102,7 @@ public:
/**
* Progress callback
*/
- void UpdateProgress(const char* msg, float prog);
+ void UpdateProgress(const std::string& msg, float prog);
protected:
// Copy the cache values from the user interface to the actual
diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx
index 68b9e6c7e..b965b32e8 100644
--- a/Source/LexerParser/cmCommandArgumentParser.cxx
+++ b/Source/LexerParser/cmCommandArgumentParser.cxx
@@ -513,7 +513,7 @@ static const yytype_uint8 yyrline[] =
static const char *const yytname[] =
{
"$end", "error", "$undefined", "cal_ENVCURLY", "cal_NCURLY",
- "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", "\"\\\\\"",
+ "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", R"("\\")",
"cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept", "Start",
"GoalWithOptionalBackSlash", "Goal", "String", "OuterText", "Variable",
"EnvVarName", "MultipleIds", "ID", YY_NULLPTR
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 9ce032384..cb89d19fd 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -2,9 +2,6 @@
# file Copyright.txt or https://cmake.org/licensing for details.
project(QtDialog)
-if(POLICY CMP0020)
- cmake_policy(SET CMP0020 NEW) # Drop when CMake >= 2.8.11 required
-endif()
CMake_OPTIONAL_COMPONENT(cmake-gui)
find_package(Qt5Widgets QUIET)
if (Qt5Widgets_FOUND)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 8d9a50ce3..c9ebba83a 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -55,6 +55,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
int main(int argc, char** argv)
{
+ cmSystemTools::EnsureStdPipes();
cmsys::Encoding::CommandLineArguments encoding_args =
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
int argc2 = encoding_args.argc();
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index 5f6ccca4b..e98cdcf4a 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -862,7 +862,7 @@ void CMakeSetupDialog::doAbout()
"built using Qt %2 (qt-project.org).\n"
#ifdef USE_LGPL
"\n"
- "The Qt Toolkit is Copyright (C) Digia Plc and/or its subsidiary(-ies).\n"
+ "The Qt Toolkit is Copyright (C) The Qt Company Ltd.\n"
"Qt is licensed under terms of the GNU LGPLv" USE_LGPL ", available at:\n"
" \"%3\""
#endif
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index f28e1a821..364a378b3 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -95,33 +95,32 @@ void StartCompilerSetup::setGenerators(
QStringList generator_list;
- std::vector<cmake::GeneratorInfo>::const_iterator it;
- for (it = gens.begin(); it != gens.end(); ++it) {
- generator_list.append(QString::fromLocal8Bit(it->name.c_str()));
+ for (cmake::GeneratorInfo const& gen : gens) {
+ generator_list.append(QString::fromLocal8Bit(gen.name.c_str()));
- if (it->supportsPlatform) {
+ if (gen.supportsPlatform) {
this->GeneratorsSupportingPlatform.append(
- QString::fromLocal8Bit(it->name.c_str()));
+ QString::fromLocal8Bit(gen.name.c_str()));
this
- ->GeneratorDefaultPlatform[QString::fromLocal8Bit(it->name.c_str())] =
- QString::fromLocal8Bit(it->defaultPlatform.c_str());
+ ->GeneratorDefaultPlatform[QString::fromLocal8Bit(gen.name.c_str())] =
+ QString::fromLocal8Bit(gen.defaultPlatform.c_str());
std::vector<std::string>::const_iterator platformIt =
- it->supportedPlatforms.cbegin();
- while (platformIt != it->supportedPlatforms.cend()) {
+ gen.supportedPlatforms.cbegin();
+ while (platformIt != gen.supportedPlatforms.cend()) {
this->GeneratorSupportedPlatforms.insert(
- QString::fromLocal8Bit(it->name.c_str()),
+ QString::fromLocal8Bit(gen.name.c_str()),
QString::fromLocal8Bit((*platformIt).c_str()));
platformIt++;
}
}
- if (it->supportsToolset) {
+ if (gen.supportsToolset) {
this->GeneratorsSupportingToolset.append(
- QString::fromLocal8Bit(it->name.c_str()));
+ QString::fromLocal8Bit(gen.name.c_str()));
}
}
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index a073c3064..f357f9032 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -25,7 +25,7 @@ QCMake::QCMake(QObject* p)
cmSystemTools::SetRunCommandHideConsole(true);
cmSystemTools::SetMessageCallback(
- [this](const char* msg, const char* title) {
+ [this](std::string const& msg, const char* title) {
this->messageCallback(msg, title);
});
cmSystemTools::SetStdoutCallback(
@@ -37,7 +37,7 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance->SetCMakeEditCommand(
cmSystemTools::GetCMakeGUICommand());
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float percent) {
+ [this](const std::string& msg, float percent) {
this->progressCallback(msg, percent);
});
@@ -48,9 +48,8 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance->GetRegisteredGenerators(
generators, /*includeNamesWithPlatform=*/false);
- std::vector<cmake::GeneratorInfo>::const_iterator it;
- for (it = generators.begin(); it != generators.end(); ++it) {
- this->AvailableGenerators.push_back(*it);
+ for (cmake::GeneratorInfo const& gen : generators) {
+ this->AvailableGenerators.push_back(gen);
}
}
@@ -234,24 +233,23 @@ void QCMake::setProperties(const QCMakePropertyList& newProps)
// set the value of properties
cmState* state = this->CMakeInstance->GetState();
std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*it);
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) {
continue;
}
QCMakeProperty prop;
- prop.Key = QString::fromLocal8Bit(it->c_str());
+ prop.Key = QString::fromLocal8Bit(key.c_str());
int idx = props.indexOf(prop);
if (idx == -1) {
- toremove.append(QString::fromLocal8Bit(it->c_str()));
+ toremove.append(QString::fromLocal8Bit(key.c_str()));
} else {
prop = props[idx];
if (prop.Value.type() == QVariant::Bool) {
- state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
+ state->SetCacheEntryValue(key, prop.Value.toBool() ? "ON" : "OFF");
} else {
- state->SetCacheEntryValue(*it,
+ state->SetCacheEntryValue(key,
prop.Value.toString().toLocal8Bit().data());
}
props.removeAt(idx);
@@ -297,22 +295,21 @@ QCMakePropertyList QCMake::properties() const
cmState* state = this->CMakeInstance->GetState();
std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
- for (std::vector<std::string>::const_iterator i = cacheKeys.begin();
- i != cacheKeys.end(); ++i) {
- cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*i);
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
}
- const char* cachedValue = state->GetCacheEntryValue(*i);
+ const char* cachedValue = state->GetCacheEntryValue(key);
QCMakeProperty prop;
- prop.Key = QString::fromLocal8Bit(i->c_str());
+ prop.Key = QString::fromLocal8Bit(key.c_str());
prop.Help =
- QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
+ QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING"));
prop.Value = QString::fromLocal8Bit(cachedValue);
- prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
+ prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
if (t == cmStateEnums::BOOL) {
prop.Type = QCMakeProperty::BOOL;
prop.Value = cmSystemTools::IsOn(cachedValue);
@@ -323,7 +320,7 @@ QCMakePropertyList QCMake::properties() const
} else if (t == cmStateEnums::STRING) {
prop.Type = QCMakeProperty::STRING;
const char* stringsProperty =
- state->GetCacheEntryProperty(*i, "STRINGS");
+ state->GetCacheEntryProperty(key, "STRINGS");
if (stringsProperty) {
prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
}
@@ -349,19 +346,19 @@ bool QCMake::interruptCallback()
#endif
}
-void QCMake::progressCallback(const char* msg, float percent)
+void QCMake::progressCallback(const std::string& msg, float percent)
{
if (percent >= 0) {
- emit this->progressChanged(QString::fromLocal8Bit(msg), percent);
+ emit this->progressChanged(QString::fromStdString(msg), percent);
} else {
- emit this->outputMessage(QString::fromLocal8Bit(msg));
+ emit this->outputMessage(QString::fromStdString(msg));
}
QCoreApplication::processEvents();
}
-void QCMake::messageCallback(const char* msg, const char* /*title*/)
+void QCMake::messageCallback(std::string const& msg, const char* /*title*/)
{
- emit this->errorMessage(QString::fromLocal8Bit(msg));
+ emit this->errorMessage(QString::fromStdString(msg));
QCoreApplication::processEvents();
}
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index ef4d2a1a1..f2fd6d923 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -168,8 +168,8 @@ protected:
cmake* CMakeInstance;
bool interruptCallback();
- void progressCallback(const char* msg, float percent);
- void messageCallback(const char* msg, const char* title);
+ void progressCallback(std::string const& msg, float percent);
+ void messageCallback(std::string const& msg, const char* title);
void stdoutCallback(std::string const& msg);
void stderrCallback(std::string const& msg);
diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx
index cb67f85d4..746fd8af2 100644
--- a/Source/QtDialog/RegexExplorer.cxx
+++ b/Source/QtDialog/RegexExplorer.cxx
@@ -20,7 +20,7 @@ void RegexExplorer::setStatusColor(QWidget* widget, bool successful)
QColor color = successful ? QColor(0, 127, 0) : Qt::red;
QPalette palette = widget->palette();
- palette.setColor(QPalette::Foreground, color);
+ palette.setColor(QPalette::WindowText, color);
widget->setPalette(palette);
}
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index a840f17c1..0be3c85e1 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -31,7 +31,7 @@ bool cmAddCustomCommandCommand::InitialPass(
return false;
}
- std::string source, target, main_dependency, working, depfile;
+ std::string source, target, main_dependency, working, depfile, job_pool;
std::string comment_buffer;
const char* comment = nullptr;
std::vector<std::string> depends, outputs, output, byproducts;
@@ -65,6 +65,7 @@ bool cmAddCustomCommandCommand::InitialPass(
doing_comment,
doing_working_directory,
doing_depfile,
+ doing_job_pool,
doing_nothing
};
@@ -81,6 +82,7 @@ bool cmAddCustomCommandCommand::InitialPass(
MAKE_STATIC_KEYWORD(DEPENDS);
MAKE_STATIC_KEYWORD(DEPFILE);
MAKE_STATIC_KEYWORD(IMPLICIT_DEPENDS);
+ MAKE_STATIC_KEYWORD(JOB_POOL);
MAKE_STATIC_KEYWORD(MAIN_DEPENDENCY);
MAKE_STATIC_KEYWORD(OUTPUT);
MAKE_STATIC_KEYWORD(OUTPUTS);
@@ -104,6 +106,7 @@ bool cmAddCustomCommandCommand::InitialPass(
keywords.insert(keyDEPENDS);
keywords.insert(keyDEPFILE);
keywords.insert(keyIMPLICIT_DEPENDS);
+ keywords.insert(keyJOB_POOL);
keywords.insert(keyMAIN_DEPENDENCY);
keywords.insert(keyOUTPUT);
keywords.insert(keyOUTPUTS);
@@ -170,6 +173,8 @@ bool cmAddCustomCommandCommand::InitialPass(
this->Makefile->GetGlobalGenerator()->GetName());
return false;
}
+ } else if (copy == keyJOB_POOL) {
+ doing = doing_job_pool;
}
} else {
std::string filename;
@@ -211,6 +216,9 @@ bool cmAddCustomCommandCommand::InitialPass(
case doing_depfile:
depfile = copy;
break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
case doing_working_directory:
working = copy;
break;
@@ -318,6 +326,11 @@ bool cmAddCustomCommandCommand::InitialPass(
return false;
}
+ if (uses_terminal && !job_pool.empty()) {
+ this->SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
// Choose which mode of the command to use.
bool escapeOldStyle = !verbatim;
if (source.empty() && output.empty()) {
@@ -325,14 +338,14 @@ bool cmAddCustomCommandCommand::InitialPass(
std::vector<std::string> no_depends;
this->Makefile->AddCustomCommandToTarget(
target, byproducts, no_depends, commandLines, cctype, comment,
- working.c_str(), escapeOldStyle, uses_terminal, depfile,
+ working.c_str(), escapeOldStyle, uses_terminal, depfile, job_pool,
command_expand_lists);
} else if (target.empty()) {
// Target is empty, use the output.
this->Makefile->AddCustomCommandToOutput(
output, byproducts, depends, main_dependency, commandLines, comment,
working.c_str(), false, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile);
+ command_expand_lists, depfile, job_pool);
// Add implicit dependency scanning requests if any were given.
if (!implicit_depends.empty()) {
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index 8240d3ef2..0ecd5f5a2 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -52,6 +52,7 @@ bool cmAddCustomTargetCommand::InitialPass(
std::string comment_buffer;
const char* comment = nullptr;
std::vector<std::string> sources;
+ std::string job_pool;
// Keep track of parser state.
enum tdoing
@@ -62,6 +63,7 @@ bool cmAddCustomTargetCommand::InitialPass(
doing_working_directory,
doing_comment,
doing_source,
+ doing_job_pool,
doing_nothing
};
tdoing doing = doing_command;
@@ -97,6 +99,8 @@ bool cmAddCustomTargetCommand::InitialPass(
command_expand_lists = true;
} else if (copy == "COMMENT") {
doing = doing_comment;
+ } else if (copy == "JOB_POOL") {
+ doing = doing_job_pool;
} else if (copy == "COMMAND") {
doing = doing_command;
@@ -137,6 +141,9 @@ bool cmAddCustomTargetCommand::InitialPass(
case doing_source:
sources.push_back(copy);
break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
default:
this->SetError("Wrong syntax. Unknown type of argument.");
return false;
@@ -200,12 +207,17 @@ bool cmAddCustomTargetCommand::InitialPass(
return true;
}
+ if (uses_terminal && !job_pool.empty()) {
+ this->SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
// Add the utility target to the makefile.
bool escapeOldStyle = !verbatim;
cmTarget* target = this->Makefile->AddUtilityCommand(
targetName, cmMakefile::TargetOrigin::Project, excludeFromAll,
working_directory.c_str(), byproducts, depends, commandLines,
- escapeOldStyle, comment, uses_terminal, command_expand_lists);
+ escapeOldStyle, comment, uses_terminal, command_expand_lists, job_pool);
// Add additional user-specified source files to the target.
target->AddSources(sources);
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
index 021bd2951..4956a471c 100644
--- a/Source/cmAddDependenciesCommand.cxx
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -6,6 +6,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmTarget.h"
class cmExecutionStatus;
@@ -27,10 +28,10 @@ bool cmAddDependenciesCommand::InitialPass(
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
if (cmTarget* target = this->Makefile->FindTargetToUse(target_name)) {
- std::vector<std::string>::const_iterator s = args.begin();
- ++s; // skip over target_name
- for (; s != args.end(); ++s) {
- target->AddUtility(*s, this->Makefile);
+
+ // skip over target_name
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ target->AddUtility(arg, this->Makefile);
}
} else {
std::ostringstream e;
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 514933303..ad12e89b9 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -4,6 +4,7 @@
#include <sstream>
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -222,7 +223,9 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
aliasedType != cmStateEnums::STATIC_LIBRARY &&
aliasedType != cmStateEnums::MODULE_LIBRARY &&
aliasedType != cmStateEnums::OBJECT_LIBRARY &&
- aliasedType != cmStateEnums::INTERFACE_LIBRARY) {
+ aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
+ !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
+ aliasedTarget->IsImported())) {
std::ostringstream e;
e << "cannot create ALIAS target \"" << libName << "\" because target \""
<< aliasedName << "\" is not a library.";
@@ -336,7 +339,7 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
return true;
}
- srclists.insert(srclists.end(), s, args.end());
+ cmAppend(srclists, s, args.end());
this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 75e5aa43f..7947188a5 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -6,6 +6,7 @@
#include <string.h>
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
class cmExecutionStatus;
@@ -26,15 +27,13 @@ bool cmAddSubDirectoryCommand::InitialPass(
bool excludeFromAll = false;
// process the rest of the arguments looking for optional args
- std::vector<std::string>::const_iterator i = args.begin();
- ++i;
- for (; i != args.end(); ++i) {
- if (*i == "EXCLUDE_FROM_ALL") {
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "EXCLUDE_FROM_ALL") {
excludeFromAll = true;
continue;
}
if (binArg.empty()) {
- binArg = *i;
+ binArg = arg;
} else {
this->SetError("called with incorrect number of arguments");
return false;
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
index 3a3afdb05..bf28702ce 100644
--- a/Source/cmAddTestCommand.cxx
+++ b/Source/cmAddTestCommand.cxx
@@ -27,8 +27,7 @@ bool cmAddTestCommand::InitialPass(std::vector<std::string> const& args,
}
// Collect the command with arguments.
- std::vector<std::string> command;
- command.insert(command.end(), args.begin() + 1, args.end());
+ std::vector<std::string> command(args.begin() + 1, args.end());
// Create the test but add a generator only the first time it is
// seen. This preserves behavior from before test generators.
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index d38b0d125..d1e32b0d4 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -5,6 +5,8 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmRange.h"
+
#include "cm_kwiml.h"
#include <algorithm>
#include <functional>
@@ -156,62 +158,29 @@ private:
};
}
-template <typename const_iterator_>
-struct cmRange
-{
- typedef const_iterator_ const_iterator;
- typedef typename std::iterator_traits<const_iterator>::value_type value_type;
- typedef typename std::iterator_traits<const_iterator>::difference_type
- difference_type;
- cmRange(const_iterator begin_, const_iterator end_)
- : Begin(begin_)
- , End(end_)
- {
- }
- const_iterator begin() const { return Begin; }
- const_iterator end() const { return End; }
- bool empty() const { return std::distance(Begin, End) == 0; }
- difference_type size() const { return std::distance(Begin, End); }
- cmRange& advance(KWIML_INT_intptr_t amount)
- {
- std::advance(Begin, amount);
- return *this;
- }
-
- cmRange& retreat(KWIML_INT_intptr_t amount)
- {
- std::advance(End, -amount);
- return *this;
- }
-
-private:
- const_iterator Begin;
- const_iterator End;
-};
-
typedef cmRange<std::vector<std::string>::const_iterator> cmStringRange;
class cmListFileBacktrace;
typedef cmRange<std::vector<cmListFileBacktrace>::const_iterator>
cmBacktraceRange;
-template <typename Iter1, typename Iter2>
-cmRange<Iter1> cmMakeRange(Iter1 begin, Iter2 end)
+template <typename Range>
+void cmDeleteAll(Range const& r)
{
- return cmRange<Iter1>(begin, end);
+ std::for_each(r.begin(), r.end(),
+ ContainerAlgorithms::DefaultDeleter<Range>());
}
-template <typename Range>
-cmRange<typename Range::const_iterator> cmMakeRange(Range const& range)
+template <typename T, typename Range>
+void cmAppend(std::vector<T>& v, Range const& r)
{
- return cmRange<typename Range::const_iterator>(range.begin(), range.end());
+ v.insert(v.end(), r.begin(), r.end());
}
-template <typename Range>
-void cmDeleteAll(Range const& r)
+template <typename T, typename InputIt>
+void cmAppend(std::vector<T>& v, InputIt first, InputIt last)
{
- std::for_each(r.begin(), r.end(),
- ContainerAlgorithms::DefaultDeleter<Range>());
+ v.insert(v.end(), first, last);
}
template <typename Range>
@@ -276,27 +245,45 @@ typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
ContainerAlgorithms::BinarySearcher<MatchRange>(m));
}
-template <typename Range>
-typename Range::const_iterator cmRemoveDuplicates(Range& r)
+template <typename ForwardIterator>
+ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
{
- typedef typename Range::value_type T;
- std::unordered_set<T> unique;
- std::vector<size_t> indices;
- size_t count = 0;
- const typename Range::const_iterator end = r.end();
- for (typename Range::const_iterator it = r.begin(); it != end;
- ++it, ++count) {
- const typename std::unordered_set<T>::iterator occur = unique.find(*it);
- if (occur == unique.end()) {
- unique.insert(*it);
- } else {
- indices.push_back(count);
+ using Value = typename std::iterator_traits<ForwardIterator>::value_type;
+ using Hash = struct
+ {
+ std::size_t operator()(ForwardIterator it) const
+ {
+ return std::hash<Value>{}(*it);
}
+ };
+
+ using Equal = struct
+ {
+ bool operator()(ForwardIterator it1, ForwardIterator it2) const
+ {
+ return *it1 == *it2;
+ }
+ };
+ std::unordered_set<ForwardIterator, Hash, Equal> uniq;
+
+ ForwardIterator result = first;
+ while (first != last) {
+ if (uniq.find(first) == uniq.end()) {
+ if (result != first) {
+ *result = std::move(*first);
+ }
+ uniq.insert(result);
+ ++result;
+ }
+ ++first;
}
- if (indices.empty()) {
- return end;
- }
- return cmRemoveIndices(r, indices);
+ return result;
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveDuplicates(Range& r)
+{
+ return cmRemoveDuplicates(r.begin(), r.end());
}
template <typename Range>
@@ -322,14 +309,6 @@ typename Range::const_iterator cmFindNot(Range const& r, T const& t)
return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
}
-template <typename Range>
-cmRange<typename Range::const_reverse_iterator> cmReverseRange(
- Range const& range)
-{
- return cmRange<typename Range::const_reverse_iterator>(range.rbegin(),
- range.rend());
-}
-
template <class Iter>
std::reverse_iterator<Iter> cmMakeReverseIterator(Iter it)
{
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index 6e5109aa1..359d57af6 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -54,6 +54,8 @@ public:
{
}
~Entry() { archive_entry_free(this->Object); }
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
operator struct archive_entry*() { return this->Object; }
};
@@ -135,6 +137,13 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
return;
}
break;
+ case CompressZstd:
+ if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_zstd: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
}
#if !defined(_WIN32) || defined(__CYGWIN__)
if (archive_read_disk_set_standard_lookup(this->Disk) != ARCHIVE_OK) {
@@ -177,12 +186,10 @@ cmArchiveWrite::~cmArchiveWrite()
bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix,
bool recursive)
{
- if (this->Okay()) {
- if (!path.empty() && path.back() == '/') {
- path.erase(path.size() - 1);
- }
- this->AddPath(path.c_str(), skip, prefix, recursive);
+ if (!path.empty() && path.back() == '/') {
+ path.erase(path.size() - 1);
}
+ this->AddPath(path.c_str(), skip, prefix, recursive);
return this->Okay();
}
@@ -218,6 +225,7 @@ bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix,
bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
{
+ this->Error = "";
// Skip the file if we have no name for it. This may happen on a
// top-level directory, which does not need to be included anyway.
if (skip >= strlen(file)) {
@@ -239,7 +247,7 @@ bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
cm_archive_entry_copy_pathname(e, dest);
if (archive_read_disk_entry_from_file(this->Disk, e, -1, nullptr) !=
ARCHIVE_OK) {
- this->Error = "archive_read_disk_entry_from_file '";
+ this->Error = "Unable to read from file '";
this->Error += file;
this->Error += "': ";
this->Error += cm_archive_error_string(this->Disk);
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
index 6ecdd630c..9ea88d3dc 100644
--- a/Source/cmArchiveWrite.h
+++ b/Source/cmArchiveWrite.h
@@ -49,7 +49,8 @@ public:
CompressGZip,
CompressBZip2,
CompressLZMA,
- CompressXZ
+ CompressXZ,
+ CompressZstd
};
/** Construct with output stream to which to write archive. */
@@ -58,6 +59,9 @@ public:
~cmArchiveWrite();
+ cmArchiveWrite(const cmArchiveWrite&) = delete;
+ cmArchiveWrite& operator=(const cmArchiveWrite&) = delete;
+
/**
* Add a path (file or directory) to the archive. Directories are
* added recursively. The "path" must be readable on disk, either
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
new file mode 100644
index 000000000..751d117f4
--- /dev/null
+++ b/Source/cmArgumentParser.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmArgumentParser.h"
+
+#include <algorithm>
+#include <type_traits>
+
+namespace ArgumentParser {
+
+auto ActionMap::Emplace(cm::string_view name, Action action)
+ -> std::pair<iterator, bool>
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name)
+ ? std::make_pair(it, false)
+ : std::make_pair(this->emplace(it, name, std::move(action)), true);
+}
+
+auto ActionMap::Find(cm::string_view name) const -> const_iterator
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name) ? it : this->end();
+}
+
+void Instance::Bind(bool& val)
+{
+ val = true;
+ this->CurrentString = nullptr;
+ this->CurrentList = nullptr;
+ this->ExpectValue = false;
+}
+
+void Instance::Bind(std::string& val)
+{
+ this->CurrentString = &val;
+ this->CurrentList = nullptr;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(StringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = &val;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(MultiStringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
+ this->ExpectValue = false;
+}
+
+void Instance::Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue)
+{
+ auto const it = this->Bindings.Find(arg);
+ if (it != this->Bindings.end()) {
+ it->second(*this, result);
+ if (this->ExpectValue && keywordsMissingValue != nullptr) {
+ keywordsMissingValue->emplace_back(arg);
+ }
+ return;
+ }
+
+ if (this->CurrentString != nullptr) {
+ this->CurrentString->assign(std::string(arg));
+ this->CurrentString = nullptr;
+ this->CurrentList = nullptr;
+ } else if (this->CurrentList != nullptr) {
+ this->CurrentList->emplace_back(arg);
+ } else if (unparsedArguments != nullptr) {
+ unparsedArguments->emplace_back(arg);
+ }
+
+ if (this->ExpectValue) {
+ if (keywordsMissingValue != nullptr) {
+ keywordsMissingValue->pop_back();
+ }
+ this->ExpectValue = false;
+ }
+}
+
+} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
new file mode 100644
index 000000000..6cfe94633
--- /dev/null
+++ b/Source/cmArgumentParser.h
@@ -0,0 +1,143 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmArgumentParser_h
+#define cmArgumentParser_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
+
+#include <cassert>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace ArgumentParser {
+
+using StringList = std::vector<std::string>;
+using MultiStringList = std::vector<StringList>;
+
+class Instance;
+using Action = std::function<void(Instance&, void*)>;
+
+// using ActionMap = cm::flat_map<cm::string_view, Action>;
+class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+{
+public:
+ std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+ const_iterator Find(cm::string_view name) const;
+};
+
+class Instance
+{
+public:
+ Instance(ActionMap const& bindings)
+ : Bindings(bindings)
+ {
+ }
+
+ void Bind(bool& val);
+ void Bind(std::string& val);
+ void Bind(StringList& val);
+ void Bind(MultiStringList& val);
+
+ void Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue);
+
+private:
+ ActionMap const& Bindings;
+ std::string* CurrentString = nullptr;
+ StringList* CurrentList = nullptr;
+ bool ExpectValue = false;
+};
+
+} // namespace ArgumentParser
+
+template <typename Result>
+class cmArgumentParser
+{
+public:
+ // I *think* this function could be made `constexpr` when the code is
+ // compiled as C++20. This would allow building a parser at compile time.
+ template <typename T>
+ cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
+ {
+ bool const inserted =
+ this->Bindings
+ .Emplace(name,
+ [member](ArgumentParser::Instance& instance, void* result) {
+ instance.Bind(static_cast<Result*>(result)->*member);
+ })
+ .second;
+ assert(inserted), (void)inserted;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Result& result, Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue);
+ }
+ }
+
+ template <typename Range>
+ Result Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ Result result;
+ this->Parse(result, args, unparsedArguments, keywordsMissingValue);
+ return result;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
+
+template <>
+class cmArgumentParser<void>
+{
+public:
+ template <typename T>
+ cmArgumentParser& Bind(cm::static_string_view name, T& ref)
+ {
+ bool const inserted = this->Bind(cm::string_view(name), ref);
+ assert(inserted), (void)inserted;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue);
+ }
+ }
+
+protected:
+ template <typename T>
+ bool Bind(cm::string_view name, T& ref)
+ {
+ return this->Bindings
+ .Emplace(name,
+ [&ref](ArgumentParser::Instance& instance, void*) {
+ instance.Bind(ref);
+ })
+ .second;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
+
+#endif
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
index 4218d810b..4b4bca243 100644
--- a/Source/cmCMakeMinimumRequired.cxx
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -55,7 +55,7 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args,
(version_min.empty() || version_max.empty())) {
std::ostringstream e;
e << "VERSION \"" << version_string
- << "\" does not have a version on both sides of \"...\".";
+ << R"(" does not have a version on both sides of "...".)";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
index ac30e1a39..8da5ef760 100644
--- a/Source/cmCMakePolicyCommand.cxx
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -176,7 +176,7 @@ bool cmCMakePolicyCommand::HandleVersionMode(
(version_min.empty() || version_max.empty())) {
std::ostringstream e;
e << "VERSION \"" << version_string
- << "\" does not have a version on both sides of \"...\".";
+ << R"(" does not have a version on both sides of "...".)";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index c0088ac5d..255a8e62a 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -167,8 +167,8 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
cmTarget* t = mf->FindLocalNonAliasTarget(tgt);
if (!t) {
cmSystemTools::Error(
- "Attempt to add link directories to non-existent target: ", tgt,
- " for directory ", d);
+ "Attempt to add link directories to non-existent target: " +
+ std::string(tgt) + " for directory " + std::string(d));
return;
}
t->InsertLinkDirectory(d, mf->GetBacktrace());
@@ -491,12 +491,16 @@ public:
typedef std::map<cmSourceFile*, cmCPluginAPISourceFile*> derived;
typedef derived::iterator iterator;
typedef derived::value_type value_type;
+ cmCPluginAPISourceFileMap() = default;
~cmCPluginAPISourceFileMap()
{
for (auto const& i : *this) {
delete i.second;
}
}
+ cmCPluginAPISourceFileMap(const cmCPluginAPISourceFileMap&) = delete;
+ cmCPluginAPISourceFileMap& operator=(const cmCPluginAPISourceFileMap&) =
+ delete;
};
cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
@@ -683,26 +687,24 @@ void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
}
// Next, try the various source extensions
- for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
- ext != sourceExts.end(); ++ext) {
+ for (std::string const& ext : sourceExts) {
hname = pathname;
hname += ".";
- hname += *ext;
+ hname += ext;
if (cmSystemTools::FileExists(hname)) {
- sf->SourceExtension = *ext;
+ sf->SourceExtension = ext;
sf->FullPath = hname;
return;
}
}
// Finally, try the various header extensions
- for (std::vector<std::string>::const_iterator ext = headerExts.begin();
- ext != headerExts.end(); ++ext) {
+ for (std::string const& ext : headerExts) {
hname = pathname;
hname += ".";
- hname += *ext;
+ hname += ext;
if (cmSystemTools::FileExists(hname)) {
- sf->SourceExtension = *ext;
+ sf->SourceExtension = ext;
sf->FullPath = hname;
return;
}
@@ -711,13 +713,11 @@ void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
std::ostringstream e;
e << "Cannot find source file \"" << pathname << "\"";
e << "\n\nTried extensions";
- for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
- ext != sourceExts.end(); ++ext) {
- e << " ." << *ext;
+ for (std::string const& ext : sourceExts) {
+ e << " ." << ext;
}
- for (std::vector<std::string>::const_iterator ext = headerExts.begin();
- ext != headerExts.end(); ++ext) {
- e << " ." << *ext;
+ for (std::string const& ext : headerExts) {
+ e << " ." << ext;
}
cmSystemTools::Error(e.str());
}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 989c7ee45..d1226c3c8 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -43,7 +43,6 @@
#include "cmCTestTestHandler.h"
#include "cmCTestUpdateHandler.h"
#include "cmCTestUploadHandler.h"
-#include "cmCurl.h"
#include "cmDynamicLoader.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
@@ -62,12 +61,149 @@
# include <be/kernel/OS.h> /* disable_debugger() API. */
#endif
-#define DEBUGOUT \
- std::cout << __LINE__ << " "; \
- std::cout
-#define DEBUGERR \
- std::cerr << __LINE__ << " "; \
- std::cerr
+struct cmCTest::Private
+{
+ /** Representation of one part. */
+ struct PartInfo
+ {
+ void SetName(const std::string& name) { this->Name = name; }
+ const std::string& GetName() const { return this->Name; }
+
+ void Enable() { this->Enabled = true; }
+ explicit operator bool() const { return this->Enabled; }
+
+ std::vector<std::string> SubmitFiles;
+
+ private:
+ bool Enabled = false;
+ std::string Name;
+ };
+
+ int RepeatTests = 1; // default to run each test once
+ bool RepeatUntilFail = false;
+ std::string ConfigType;
+ std::string ScheduleType;
+ std::chrono::system_clock::time_point StopTime;
+ bool TestProgressOutput = false;
+ bool Verbose = false;
+ bool ExtraVerbose = false;
+ bool ProduceXML = false;
+ bool LabelSummary = true;
+ bool SubprojectSummary = true;
+ bool UseHTTP10 = false;
+ bool PrintLabels = false;
+ bool Failover = false;
+
+ bool FlushTestProgressLine = false;
+
+ bool ForceNewCTestProcess = false;
+
+ bool RunConfigurationScript = false;
+
+ // these are helper classes
+ cmCTestBuildHandler BuildHandler;
+ cmCTestBuildAndTestHandler BuildAndTestHandler;
+ cmCTestCoverageHandler CoverageHandler;
+ cmCTestScriptHandler ScriptHandler;
+ cmCTestTestHandler TestHandler;
+ cmCTestUpdateHandler UpdateHandler;
+ cmCTestConfigureHandler ConfigureHandler;
+ cmCTestMemCheckHandler MemCheckHandler;
+ cmCTestSubmitHandler SubmitHandler;
+ cmCTestUploadHandler UploadHandler;
+
+ std::vector<cmCTestGenericHandler*> GetTestingHandlers()
+ {
+ return { &this->BuildHandler, &this->BuildAndTestHandler,
+ &this->CoverageHandler, &this->ScriptHandler,
+ &this->TestHandler, &this->UpdateHandler,
+ &this->ConfigureHandler, &this->MemCheckHandler,
+ &this->SubmitHandler, &this->UploadHandler };
+ }
+
+ std::map<std::string, cmCTestGenericHandler*> GetNamedTestingHandlers()
+ {
+ return { { "build", &this->BuildHandler },
+ { "buildtest", &this->BuildAndTestHandler },
+ { "coverage", &this->CoverageHandler },
+ { "script", &this->ScriptHandler },
+ { "test", &this->TestHandler },
+ { "update", &this->UpdateHandler },
+ { "configure", &this->ConfigureHandler },
+ { "memcheck", &this->MemCheckHandler },
+ { "submit", &this->SubmitHandler },
+ { "upload", &this->UploadHandler } };
+ }
+
+ bool ShowOnly = false;
+ bool OutputAsJson = false;
+ int OutputAsJsonVersion = 1;
+
+ // TODO: The ctest configuration should be a hierarchy of
+ // configuration option sources: command-line, script, ini file.
+ // Then the ini file can get re-loaded whenever it changes without
+ // affecting any higher-precedence settings.
+ std::map<std::string, std::string> CTestConfiguration;
+ std::map<std::string, std::string> CTestConfigurationOverwrites;
+
+ PartInfo Parts[PartCount];
+ std::map<std::string, Part> PartMap;
+
+ std::string CurrentTag;
+ bool TomorrowTag = false;
+
+ int TestModel = cmCTest::EXPERIMENTAL;
+ std::string SpecificTrack;
+
+ cmDuration TimeOut = cmDuration::zero();
+
+ cmDuration GlobalTimeout = cmDuration::zero();
+
+ int MaxTestNameWidth = 30;
+
+ int ParallelLevel = 1;
+ bool ParallelLevelSetInCli = false;
+
+ unsigned long TestLoad = 0;
+
+ int CompatibilityMode;
+
+ // information for the --build-and-test options
+ std::string BinaryDir;
+
+ std::string NotesFiles;
+
+ bool InteractiveDebugMode = true;
+
+ bool ShortDateFormat = true;
+
+ bool CompressXMLFiles = false;
+ bool CompressTestOutput = true;
+
+ // By default we write output to the process output streams.
+ std::ostream* StreamOut = &std::cout;
+ std::ostream* StreamErr = &std::cerr;
+
+ bool SuppressUpdatingCTestConfiguration = false;
+
+ bool Debug = false;
+ bool ShowLineNumbers = false;
+ bool Quiet = false;
+
+ std::string BuildID;
+
+ std::vector<std::string> InitialCommandLineArguments;
+
+ int SubmitIndex = 0;
+
+ cmGeneratedFileStream* OutputLogFile = nullptr;
+ int OutputLogFileLastTag = -1;
+
+ bool OutputTestOutputOnTestFailure = false;
+ bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
+
+ std::map<std::string, std::string> Definitions;
+};
struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
{
@@ -123,6 +259,11 @@ struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
return lctime;
}
+bool cmCTest::GetTomorrowTag() const
+{
+ return this->Impl->TomorrowTag;
+}
+
std::string cmCTest::CleanString(const std::string& str)
{
std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
@@ -142,7 +283,7 @@ std::string cmCTest::CurrentTime()
struct tm* t = localtime(&currenttime);
// return ::CleanString(ctime(&currenttime));
char current_time[1024];
- if (this->ShortDateFormat) {
+ if (this->Impl->ShortDateFormat) {
strftime(current_time, 1000, "%b %d %H:%M %Z", t);
} else {
strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
@@ -160,88 +301,6 @@ std::string cmCTest::GetCostDataFile()
return fname;
}
-#ifdef CMAKE_BUILD_WITH_CMAKE
-static size_t HTTPResponseCallback(void* ptr, size_t size, size_t nmemb,
- void* data)
-{
- int realsize = static_cast<int>(size * nmemb);
-
- std::string* response = static_cast<std::string*>(data);
- const char* chPtr = static_cast<char*>(ptr);
- *response += chPtr;
-
- return realsize;
-}
-
-int cmCTest::HTTPRequest(std::string url, HTTPMethod method,
- std::string& response, std::string const& fields,
- std::string const& putFile, int timeout)
-{
- CURL* curl;
- FILE* file;
- ::curl_global_init(CURL_GLOBAL_ALL);
- curl = ::curl_easy_init();
- cmCurlSetCAInfo(curl);
-
- // set request options based on method
- switch (method) {
- case cmCTest::HTTP_POST:
- ::curl_easy_setopt(curl, CURLOPT_POST, 1);
- ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str());
- break;
- case cmCTest::HTTP_PUT:
- if (!cmSystemTools::FileExists(putFile)) {
- response = "Error: File ";
- response += putFile + " does not exist.\n";
- return -1;
- }
- ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
- file = cmsys::SystemTools::Fopen(putFile, "rb");
- ::curl_easy_setopt(curl, CURLOPT_INFILE, file);
- // fall through to append GET fields
- CM_FALLTHROUGH;
- case cmCTest::HTTP_GET:
- if (!fields.empty()) {
- url += "?" + fields;
- }
- break;
- }
-
- ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
- ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
- ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
- // set response options
- ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTPResponseCallback);
- ::curl_easy_setopt(curl, CURLOPT_FILE, &response);
- ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
-
- CURLcode res = ::curl_easy_perform(curl);
-
- ::curl_easy_cleanup(curl);
- ::curl_global_cleanup();
-
- return static_cast<int>(res);
-}
-#endif
-
-std::string cmCTest::MakeURLSafe(const std::string& str)
-{
- std::ostringstream ost;
- char buffer[10];
- for (unsigned char ch : str) {
- if ((ch > 126 || ch < 32 || ch == '&' || ch == '%' || ch == '+' ||
- ch == '=' || ch == '@') &&
- ch != 9) {
- sprintf(buffer, "%02x;", static_cast<unsigned int>(ch));
- ost << buffer;
- } else {
- ost << ch;
- }
- }
- return ost.str();
-}
-
std::string cmCTest::DecodeURL(const std::string& in)
{
std::string out;
@@ -258,92 +317,39 @@ std::string cmCTest::DecodeURL(const std::string& in)
}
cmCTest::cmCTest()
+ : Impl(new Private)
{
- this->LabelSummary = true;
- this->SubprojectSummary = true;
- this->ParallelLevel = 1;
- this->ParallelLevelSetInCli = false;
- this->TestLoad = 0;
- this->SubmitIndex = 0;
- this->Failover = false;
- this->ForceNewCTestProcess = false;
- this->TomorrowTag = false;
- this->TestProgressOutput = false;
- this->FlushTestProgressLine = false;
- this->Verbose = false;
-
- this->Debug = false;
- this->ShowLineNumbers = false;
- this->Quiet = false;
- this->ExtraVerbose = false;
- this->ProduceXML = false;
- this->ShowOnly = false;
- this->OutputAsJson = false;
- this->OutputAsJsonVersion = 1;
- this->RunConfigurationScript = false;
- this->UseHTTP10 = false;
- this->PrintLabels = false;
- this->CompressTestOutput = true;
- this->TestModel = cmCTest::EXPERIMENTAL;
- this->MaxTestNameWidth = 30;
- this->InteractiveDebugMode = true;
- this->TimeOut = cmDuration::zero();
- this->GlobalTimeout = cmDuration::zero();
- this->CompressXMLFiles = false;
- this->ScheduleType.clear();
- this->OutputLogFile = nullptr;
- this->OutputLogFileLastTag = -1;
- this->SuppressUpdatingCTestConfiguration = false;
- this->BuildID = "";
- this->OutputTestOutputOnTestFailure = false;
- this->OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
- this->RepeatTests = 1; // default to run each test once
- this->RepeatUntilFail = false;
-
std::string envValue;
if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", envValue)) {
- this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(envValue);
+ this->Impl->OutputTestOutputOnTestFailure =
+ !cmSystemTools::IsOff(envValue);
}
envValue.clear();
if (cmSystemTools::GetEnv("CTEST_PROGRESS_OUTPUT", envValue)) {
- this->TestProgressOutput = !cmSystemTools::IsOff(envValue);
- }
-
- this->InitStreams();
-
- this->Parts[PartStart].SetName("Start");
- this->Parts[PartUpdate].SetName("Update");
- this->Parts[PartConfigure].SetName("Configure");
- this->Parts[PartBuild].SetName("Build");
- this->Parts[PartTest].SetName("Test");
- this->Parts[PartCoverage].SetName("Coverage");
- this->Parts[PartMemCheck].SetName("MemCheck");
- this->Parts[PartSubmit].SetName("Submit");
- this->Parts[PartNotes].SetName("Notes");
- this->Parts[PartExtraFiles].SetName("ExtraFiles");
- this->Parts[PartUpload].SetName("Upload");
- this->Parts[PartDone].SetName("Done");
+ this->Impl->TestProgressOutput = !cmSystemTools::IsOff(envValue);
+ }
+
+ this->Impl->Parts[PartStart].SetName("Start");
+ this->Impl->Parts[PartUpdate].SetName("Update");
+ this->Impl->Parts[PartConfigure].SetName("Configure");
+ this->Impl->Parts[PartBuild].SetName("Build");
+ this->Impl->Parts[PartTest].SetName("Test");
+ this->Impl->Parts[PartCoverage].SetName("Coverage");
+ this->Impl->Parts[PartMemCheck].SetName("MemCheck");
+ this->Impl->Parts[PartSubmit].SetName("Submit");
+ this->Impl->Parts[PartNotes].SetName("Notes");
+ this->Impl->Parts[PartExtraFiles].SetName("ExtraFiles");
+ this->Impl->Parts[PartUpload].SetName("Upload");
+ this->Impl->Parts[PartDone].SetName("Done");
// Fill the part name-to-id map.
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
+ this->Impl
+ ->PartMap[cmSystemTools::LowerCase(this->Impl->Parts[p].GetName())] = p;
}
- this->ShortDateFormat = true;
-
- this->TestingHandlers["build"] = new cmCTestBuildHandler;
- this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
- this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
- this->TestingHandlers["script"] = new cmCTestScriptHandler;
- this->TestingHandlers["test"] = new cmCTestTestHandler;
- this->TestingHandlers["update"] = new cmCTestUpdateHandler;
- this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
- this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
- this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
- this->TestingHandlers["upload"] = new cmCTestUploadHandler;
-
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetCTestInstance(this);
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetCTestInstance(this);
}
// Make sure we can capture the build tool output.
@@ -352,31 +358,40 @@ cmCTest::cmCTest()
cmCTest::~cmCTest()
{
- cmDeleteAll(this->TestingHandlers);
- this->SetOutputLogFileName(nullptr);
+ delete this->Impl->OutputLogFile;
+}
+
+int cmCTest::GetParallelLevel() const
+{
+ return this->Impl->ParallelLevel;
}
void cmCTest::SetParallelLevel(int level)
{
- this->ParallelLevel = level < 1 ? 1 : level;
+ this->Impl->ParallelLevel = level < 1 ? 1 : level;
+}
+
+unsigned long cmCTest::GetTestLoad() const
+{
+ return this->Impl->TestLoad;
}
void cmCTest::SetTestLoad(unsigned long load)
{
- this->TestLoad = load;
+ this->Impl->TestLoad = load;
}
bool cmCTest::ShouldCompressTestOutput()
{
- return this->CompressTestOutput;
+ return this->Impl->CompressTestOutput;
}
cmCTest::Part cmCTest::GetPartFromName(const char* name)
{
// Look up by lower-case to make names case-insensitive.
std::string lower_name = cmSystemTools::LowerCase(name);
- PartMapType::const_iterator i = this->PartMap.find(lower_name);
- if (i != this->PartMap.end()) {
+ auto const i = this->Impl->PartMap.find(lower_name);
+ if (i != this->Impl->PartMap.end()) {
return i->second;
}
@@ -392,19 +407,19 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
}
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- if (!this->InteractiveDebugMode) {
+ if (!this->Impl->InteractiveDebugMode) {
this->BlockTestErrorDiagnostics();
} else {
cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
}
- this->BinaryDir = binary_dir;
- cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
+ this->Impl->BinaryDir = binary_dir;
+ cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
this->UpdateCTestConfiguration();
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
cmCTestOptionalLog(this, OUTPUT,
" Site: "
@@ -415,7 +430,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
<< std::endl,
quiet);
cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
- if (this->TestModel == cmCTest::NIGHTLY &&
+ if (this->Impl->TestModel == cmCTest::NIGHTLY &&
this->GetCTestConfiguration("NightlyStartTime").empty()) {
cmCTestOptionalLog(
this, WARNING,
@@ -435,17 +450,18 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmMakefile mf(&gg, cm.GetCurrentSnapshot());
- if (!this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), &mf)) {
+ if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir.c_str(),
+ &mf)) {
cmCTestOptionalLog(
this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
quiet);
return 0;
}
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
// Verify "Testing" directory exists:
//
- std::string testingDir = this->BinaryDir + "/Testing";
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
if (cmSystemTools::FileExists(testingDir)) {
if (!cmSystemTools::FileIsDirectory(testingDir)) {
cmCTestLog(this, ERROR_MESSAGE,
@@ -475,7 +491,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
if (createNewTag) {
time_t tctime = time(nullptr);
- if (this->TomorrowTag) {
+ if (this->Impl->TomorrowTag) {
tctime += (24 * 60 * 60);
}
struct tm* lctime = gmtime(&tctime);
@@ -493,26 +509,28 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
}
std::string track;
if (cmSystemTools::GetLineFromStream(tfin, track) &&
- !this->Parts[PartStart] && !command) {
- this->SpecificTrack = track;
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->SpecificTrack = track;
}
std::string model;
if (cmSystemTools::GetLineFromStream(tfin, model) &&
- !this->Parts[PartStart] && !command) {
- this->TestModel = GetTestModelFromString(model.c_str());
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->TestModel = GetTestModelFromString(model.c_str());
}
tfin.close();
}
- if (tag.empty() || (nullptr != command) || this->Parts[PartStart]) {
+ if (tag.empty() || (nullptr != command) ||
+ this->Impl->Parts[PartStart]) {
cmCTestOptionalLog(
this, DEBUG,
"TestModel: " << this->GetTestModelString() << std::endl, quiet);
- cmCTestOptionalLog(
- this, DEBUG, "TestModel: " << this->TestModel << std::endl, quiet);
- if (this->TestModel == cmCTest::NIGHTLY) {
+ cmCTestOptionalLog(this, DEBUG,
+ "TestModel: " << this->Impl->TestModel << std::endl,
+ quiet);
+ if (this->Impl->TestModel == cmCTest::NIGHTLY) {
lctime = this->GetNightlyTime(
this->GetCTestConfiguration("NightlyStartTime"),
- this->TomorrowTag);
+ this->Impl->TomorrowTag);
}
char datestring[100];
sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900,
@@ -523,7 +541,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
if (ofs) {
ofs << tag << std::endl;
ofs << this->GetTestModelString() << std::endl;
- switch (this->TestModel) {
+ switch (this->Impl->TestModel) {
case cmCTest::EXPERIMENTAL:
ofs << "Experimental" << std::endl;
break;
@@ -565,7 +583,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
return 0;
}
- if (this->TestModel == cmCTest::UNKNOWN) {
+ if (this->Impl->TestModel == cmCTest::UNKNOWN) {
if (model == cmCTest::UNKNOWN) {
cmCTestLog(this, ERROR_MESSAGE,
"TAG file does not contain model and "
@@ -577,8 +595,8 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
this->SetTestModel(model);
}
- if (model != this->TestModel && model != cmCTest::UNKNOWN &&
- this->TestModel != cmCTest::UNKNOWN) {
+ if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
+ this->Impl->TestModel != cmCTest::UNKNOWN) {
cmCTestOptionalLog(this, WARNING,
"Model given in TAG does not match "
"model given in ctest_start()"
@@ -586,14 +604,15 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
quiet);
}
- if (!this->SpecificTrack.empty() && track != this->SpecificTrack) {
+ if (!this->Impl->SpecificTrack.empty() &&
+ track != this->Impl->SpecificTrack) {
cmCTestOptionalLog(this, WARNING,
"Track given in TAG does not match "
"track given in ctest_start()"
<< std::endl,
quiet);
} else {
- this->SpecificTrack = track;
+ this->Impl->SpecificTrack = track;
}
cmCTestOptionalLog(this, OUTPUT,
@@ -603,7 +622,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
quiet);
}
- this->CurrentTag = tag;
+ this->Impl->CurrentTag = tag;
}
return 1;
@@ -613,9 +632,9 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
{
std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
- this->BuildID = "";
+ this->Impl->BuildID = "";
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->Parts[p].SubmitFiles.clear();
+ this->Impl->Parts[p].SubmitFiles.clear();
}
cmMakefile* mf = command->GetMakefile();
@@ -669,18 +688,18 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
bool cmCTest::UpdateCTestConfiguration()
{
- if (this->SuppressUpdatingCTestConfiguration) {
+ if (this->Impl->SuppressUpdatingCTestConfiguration) {
return true;
}
- std::string fileName = this->BinaryDir + "/CTestConfiguration.ini";
+ std::string fileName = this->Impl->BinaryDir + "/CTestConfiguration.ini";
if (!cmSystemTools::FileExists(fileName)) {
- fileName = this->BinaryDir + "/DartConfiguration.tcl";
+ fileName = this->Impl->BinaryDir + "/DartConfiguration.tcl";
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"UpdateCTestConfiguration from :" << fileName << "\n");
if (!cmSystemTools::FileExists(fileName)) {
// No need to exit if we are not producing XML
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
cmCTestLog(this, ERROR_MESSAGE,
"Cannot find file: " << fileName << std::endl);
return false;
@@ -720,15 +739,15 @@ bool cmCTest::UpdateCTestConfiguration()
}
std::string key = line.substr(0, cpos);
std::string value = cmCTest::CleanString(line.substr(cpos + 1));
- this->CTestConfiguration[key] = value;
+ this->Impl->CTestConfiguration[key] = value;
}
fin.close();
}
if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
- this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
- cmSystemTools::ChangeDirectory(this->BinaryDir);
+ this->Impl->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
+ cmSystemTools::ChangeDirectory(this->Impl->BinaryDir);
}
- this->TimeOut =
+ this->Impl->TimeOut =
std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str()));
std::string const& testLoad = this->GetCTestConfiguration("TestLoad");
if (!testLoad.empty()) {
@@ -740,8 +759,8 @@ bool cmCTest::UpdateCTestConfiguration()
"Invalid value for 'Test Load' : " << testLoad << std::endl);
}
}
- if (this->ProduceXML) {
- this->CompressXMLFiles =
+ if (this->Impl->ProduceXML) {
+ this->Impl->CompressXMLFiles =
cmSystemTools::IsOn(this->GetCTestConfiguration("CompressSubmission"));
}
return true;
@@ -760,21 +779,26 @@ void cmCTest::BlockTestErrorDiagnostics()
void cmCTest::SetTestModel(int mode)
{
- this->InteractiveDebugMode = false;
- this->TestModel = mode;
+ this->Impl->InteractiveDebugMode = false;
+ this->Impl->TestModel = mode;
+}
+
+int cmCTest::GetTestModel() const
+{
+ return this->Impl->TestModel;
}
bool cmCTest::SetTest(const char* ttype, bool report)
{
if (cmSystemTools::LowerCase(ttype) == "all") {
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->Parts[p].Enable();
+ this->Impl->Parts[p].Enable();
}
return true;
}
Part p = this->GetPartFromName(ttype);
if (p != PartCount) {
- this->Parts[p].Enable();
+ this->Impl->Parts[p].Enable();
return true;
}
if (report) {
@@ -792,7 +816,7 @@ void cmCTest::Finalize()
bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
cmGeneratedFileStream& stream, bool compress)
{
- std::string testingDir = this->BinaryDir + "/Testing";
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
if (!path.empty()) {
testingDir += "/" + path;
}
@@ -819,7 +843,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
return false;
}
if (compress) {
- if (this->CompressXMLFiles) {
+ if (this->Impl->CompressXMLFiles) {
stream.SetCompression(true);
}
}
@@ -844,40 +868,59 @@ bool cmCTest::AddIfExists(Part part, const char* file)
bool cmCTest::CTestFileExists(const std::string& filename)
{
- std::string testingDir =
- this->BinaryDir + "/Testing/" + this->CurrentTag + "/" + filename;
+ std::string testingDir = this->Impl->BinaryDir + "/Testing/" +
+ this->Impl->CurrentTag + "/" + filename;
return cmSystemTools::FileExists(testingDir);
}
-cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
+cmCTestBuildHandler* cmCTest::GetBuildHandler()
{
- cmCTest::t_TestingHandlers::iterator it =
- this->TestingHandlers.find(handler);
- if (it == this->TestingHandlers.end()) {
- return nullptr;
- }
- it->second->Initialize();
- return it->second;
+ return &this->Impl->BuildHandler;
}
-cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
+cmCTestBuildAndTestHandler* cmCTest::GetBuildAndTestHandler()
{
- cmCTest::t_TestingHandlers::iterator it =
- this->TestingHandlers.find(handler);
- if (it == this->TestingHandlers.end()) {
- return nullptr;
- }
- return it->second;
+ return &this->Impl->BuildAndTestHandler;
}
-int cmCTest::ExecuteHandler(const char* shandler)
+cmCTestCoverageHandler* cmCTest::GetCoverageHandler()
{
- cmCTestGenericHandler* handler = this->GetHandler(shandler);
- if (!handler) {
- return -1;
- }
- handler->Initialize();
- return handler->ProcessHandler();
+ return &this->Impl->CoverageHandler;
+}
+
+cmCTestScriptHandler* cmCTest::GetScriptHandler()
+{
+ return &this->Impl->ScriptHandler;
+}
+
+cmCTestTestHandler* cmCTest::GetTestHandler()
+{
+ return &this->Impl->TestHandler;
+}
+
+cmCTestUpdateHandler* cmCTest::GetUpdateHandler()
+{
+ return &this->Impl->UpdateHandler;
+}
+
+cmCTestConfigureHandler* cmCTest::GetConfigureHandler()
+{
+ return &this->Impl->ConfigureHandler;
+}
+
+cmCTestMemCheckHandler* cmCTest::GetMemCheckHandler()
+{
+ return &this->Impl->MemCheckHandler;
+}
+
+cmCTestSubmitHandler* cmCTest::GetSubmitHandler()
+{
+ return &this->Impl->SubmitHandler;
+}
+
+cmCTestUploadHandler* cmCTest::GetUploadHandler()
+{
+ return &this->Impl->UploadHandler;
}
int cmCTest::ProcessSteps()
@@ -887,11 +930,11 @@ int cmCTest::ProcessSteps()
int update_count = 0;
for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) {
- notest = !this->Parts[p];
+ notest = !this->Impl->Parts[p];
}
- if (this->Parts[PartUpdate] &&
+ if (this->Impl->Parts[PartUpdate] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- cmCTestGenericHandler* uphandler = this->GetHandler("update");
+ cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
uphandler->SetPersistentOption(
"SourceDirectory",
this->GetCTestConfiguration("SourceDirectory").c_str());
@@ -900,45 +943,45 @@ int cmCTest::ProcessSteps()
res |= cmCTest::UPDATE_ERRORS;
}
}
- if (this->TestModel == cmCTest::CONTINUOUS && !update_count) {
+ if (this->Impl->TestModel == cmCTest::CONTINUOUS && !update_count) {
return 0;
}
- if (this->Parts[PartConfigure] &&
+ if (this->Impl->Parts[PartConfigure] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- if (this->GetHandler("configure")->ProcessHandler() < 0) {
+ if (this->GetConfigureHandler()->ProcessHandler() < 0) {
res |= cmCTest::CONFIGURE_ERRORS;
}
}
- if (this->Parts[PartBuild] &&
+ if (this->Impl->Parts[PartBuild] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("build")->ProcessHandler() < 0) {
+ if (this->GetBuildHandler()->ProcessHandler() < 0) {
res |= cmCTest::BUILD_ERRORS;
}
}
- if ((this->Parts[PartTest] || notest) &&
+ if ((this->Impl->Parts[PartTest] || notest) &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("test")->ProcessHandler() < 0) {
+ if (this->GetTestHandler()->ProcessHandler() < 0) {
res |= cmCTest::TEST_ERRORS;
}
}
- if (this->Parts[PartCoverage] &&
+ if (this->Impl->Parts[PartCoverage] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("coverage")->ProcessHandler() < 0) {
+ if (this->GetCoverageHandler()->ProcessHandler() < 0) {
res |= cmCTest::COVERAGE_ERRORS;
}
}
- if (this->Parts[PartMemCheck] &&
+ if (this->Impl->Parts[PartMemCheck] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("memcheck")->ProcessHandler() < 0) {
+ if (this->GetMemCheckHandler()->ProcessHandler() < 0) {
res |= cmCTest::MEMORY_ERRORS;
}
}
if (!notest) {
- std::string notes_dir = this->BinaryDir + "/Testing/Notes";
+ std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
if (cmSystemTools::FileIsDirectory(notes_dir)) {
cmsys::Directory d;
d.Load(notes_dir);
@@ -948,24 +991,24 @@ int cmCTest::ProcessSteps()
std::string fullname = notes_dir + "/" + file;
if (cmSystemTools::FileExists(fullname) &&
!cmSystemTools::FileIsDirectory(fullname)) {
- if (!this->NotesFiles.empty()) {
- this->NotesFiles += ";";
+ if (!this->Impl->NotesFiles.empty()) {
+ this->Impl->NotesFiles += ";";
}
- this->NotesFiles += fullname;
- this->Parts[PartNotes].Enable();
+ this->Impl->NotesFiles += fullname;
+ this->Impl->Parts[PartNotes].Enable();
}
}
}
}
- if (this->Parts[PartNotes]) {
+ if (this->Impl->Parts[PartNotes]) {
this->UpdateCTestConfiguration();
- if (!this->NotesFiles.empty()) {
- this->GenerateNotesFile(this->NotesFiles.c_str());
+ if (!this->Impl->NotesFiles.empty()) {
+ this->GenerateNotesFile(this->Impl->NotesFiles.c_str());
}
}
- if (this->Parts[PartSubmit]) {
+ if (this->Impl->Parts[PartSubmit]) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("submit")->ProcessHandler() < 0) {
+ if (this->GetSubmitHandler()->ProcessHandler() < 0) {
res |= cmCTest::SUBMIT_ERRORS;
}
}
@@ -977,10 +1020,10 @@ int cmCTest::ProcessSteps()
std::string cmCTest::GetTestModelString()
{
- if (!this->SpecificTrack.empty()) {
- return this->SpecificTrack;
+ if (!this->Impl->SpecificTrack.empty()) {
+ return this->Impl->SpecificTrack;
}
- switch (this->TestModel) {
+ switch (this->Impl->TestModel) {
case cmCTest::NIGHTLY:
return "Nightly";
case cmCTest::CONTINUOUS:
@@ -1009,7 +1052,7 @@ int cmCTest::GetTestModelFromString(const char* str)
//######################################################################
//######################################################################
-int cmCTest::RunMakeCommand(const char* command, std::string& output,
+int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
int* retVal, const char* dir, cmDuration timeout,
std::ostream& ofs, Encoding encoding)
{
@@ -1039,7 +1082,7 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output,
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, timeout.count());
@@ -1139,8 +1182,9 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
if (timeout != cmCTest::MaxDuration()) {
timeout -= std::chrono::minutes(2);
}
- if (this->TimeOut > cmDuration::zero() && this->TimeOut < timeout) {
- timeout = this->TimeOut;
+ if (this->Impl->TimeOut > cmDuration::zero() &&
+ this->Impl->TimeOut < timeout) {
+ timeout = this->Impl->TimeOut;
}
if (testTimeOut > cmDuration::zero() &&
testTimeOut < this->GetRemainingTimeAllowed()) {
@@ -1158,10 +1202,10 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
: std::to_string(cmDurationTo<unsigned int>(timeout)))
<< "\n");
if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
- !this->ForceNewCTestProcess) {
+ !this->Impl->ForceNewCTestProcess) {
cmCTest inst;
- inst.ConfigType = this->ConfigType;
- inst.TimeOut = timeout;
+ inst.Impl->ConfigType = this->Impl->ConfigType;
+ inst.Impl->TimeOut = timeout;
// Capture output of the child ctest.
std::ostringstream oss;
@@ -1222,7 +1266,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
}
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -1238,7 +1282,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
processOutput.DecodeText(data, length, strdata);
if (output) {
- tempOutput.insert(tempOutput.end(), data, data + length);
+ cmAppend(tempOutput, data, data + length);
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
cmCTestLogWrite(strdata.c_str(), strdata.size()));
@@ -1258,7 +1302,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
cmsysProcess_WaitForExit(cp, nullptr);
processOutput.DecodeText(tempOutput, tempOutput);
if (output && tempOutput.begin() != tempOutput.end()) {
- output->append(&*tempOutput.begin(), tempOutput.size());
+ output->append(tempOutput.data(), tempOutput.size());
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"-- Process completed" << std::endl);
@@ -1267,11 +1311,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->OutputTestOutputOnTestFailure) {
+ if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
OutputTestErrors(tempOutput);
}
} else if (result == cmsysProcess_State_Exception) {
- if (this->OutputTestOutputOnTestFailure) {
+ if (this->Impl->OutputTestOutputOnTestFailure) {
OutputTestErrors(tempOutput);
}
*retVal = cmsysProcess_GetExitException(cp);
@@ -1330,7 +1374,7 @@ std::string cmCTest::SafeBuildIdField(const std::string& value)
void cmCTest::StartXML(cmXMLWriter& xml, bool append)
{
- if (this->CurrentTag.empty()) {
+ if (this->Impl->CurrentTag.empty()) {
cmCTestLog(this, ERROR_MESSAGE,
"Current Tag empty, this may mean"
" NightlStartTime was not set correctly."
@@ -1346,7 +1390,7 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append)
std::string buildname =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
- std::string stamp = cmCTest::SafeBuildIdField(this->CurrentTag + "-" +
+ std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
this->GetTestModelString());
std::string site =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
@@ -1394,8 +1438,7 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append)
void cmCTest::AddSiteProperties(cmXMLWriter& xml)
{
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
cmake* cm = ch->GetCMake();
// if no CMake then this is the old style script and props like
// this will not work anyway.
@@ -1465,7 +1508,7 @@ void cmCTest::EndXML(cmXMLWriter& xml)
}
int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
- const cmCTest::VectorOfStrings& files)
+ std::vector<std::string> const& files)
{
std::string buildname =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
@@ -1477,10 +1520,10 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
xml.StartElement("Site");
xml.Attribute("BuildName", buildname);
xml.Attribute("BuildStamp",
- this->CurrentTag + "-" + this->GetTestModelString());
+ this->Impl->CurrentTag + "-" + this->GetTestModelString());
xml.Attribute("Name", this->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->AddSiteProperties(xml);
xml.StartElement("Notes");
@@ -1515,10 +1558,10 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
return 1;
}
-int cmCTest::GenerateNotesFile(const VectorOfStrings& files)
+int cmCTest::GenerateNotesFile(std::vector<std::string> const& files)
{
cmGeneratedFileStream ofs;
- if (!this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs)) {
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Notes.xml", ofs)) {
cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
return 1;
}
@@ -1533,11 +1576,10 @@ int cmCTest::GenerateNotesFile(const char* cfiles)
return 1;
}
- VectorOfStrings files;
-
cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
- files = cmSystemTools::SplitString(cfiles, ';');
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
if (files.empty()) {
return 1;
}
@@ -1548,14 +1590,14 @@ int cmCTest::GenerateNotesFile(const char* cfiles)
int cmCTest::GenerateDoneFile()
{
cmGeneratedFileStream ofs;
- if (!this->OpenOutputFile(this->CurrentTag, "Done.xml", ofs)) {
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Done.xml", ofs)) {
cmCTestLog(this, ERROR_MESSAGE, "Cannot open done file" << std::endl);
return 1;
}
cmXMLWriter xml(ofs);
xml.StartDocument();
xml.StartElement("Done");
- xml.Element("buildId", this->BuildID);
+ xml.Element("buildId", this->Impl->BuildID);
xml.Element("time", std::chrono::system_clock::now());
xml.EndElement(); // Done
xml.EndDocument();
@@ -1569,8 +1611,8 @@ std::string cmCTest::Base64GzipEncodeFile(std::string const& file)
std::vector<std::string> files;
files.push_back(file);
- if (!cmSystemTools::CreateTar(tarFile.c_str(), files,
- cmSystemTools::TarCompressGZip, false)) {
+ if (!cmSystemTools::CreateTar(tarFile, files, cmSystemTools::TarCompressGZip,
+ false)) {
cmCTestLog(this, ERROR_MESSAGE,
"Error creating tar while "
"encoding file: "
@@ -1604,7 +1646,7 @@ std::string cmCTest::Base64EncodeFile(std::string const& file)
return std::string(&encoded_buffer[0], rlen);
}
-bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files)
+bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files)
{
for (std::string const& file : files) {
if (!cmSystemTools::FileExists(file)) {
@@ -1624,11 +1666,10 @@ bool cmCTest::SubmitExtraFiles(const char* cfiles)
return true;
}
- VectorOfStrings files;
-
cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
- files = cmSystemTools::SplitString(cfiles, ';');
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
if (files.empty()) {
return true;
}
@@ -1796,17 +1837,17 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
{
std::string arg = args[i];
if (this->CheckArgument(arg, "-F")) {
- this->Failover = true;
+ this->Impl->Failover = true;
}
if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) {
i++;
int plevel = atoi(args[i].c_str());
this->SetParallelLevel(plevel);
- this->ParallelLevelSetInCli = true;
+ this->Impl->ParallelLevelSetInCli = true;
} else if (arg.find("-j") == 0) {
int plevel = atoi(arg.substr(2).c_str());
this->SetParallelLevel(plevel);
- this->ParallelLevelSetInCli = true;
+ this->Impl->ParallelLevelSetInCli = true;
}
if (this->CheckArgument(arg, "--repeat-until-fail")) {
if (i >= args.size() - 1) {
@@ -1820,9 +1861,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
"'--repeat-until-fail' given non-integer value '" + args[i] + "'";
return false;
}
- this->RepeatTests = static_cast<int>(repeat);
+ this->Impl->RepeatTests = static_cast<int>(repeat);
if (repeat > 1) {
- this->RepeatUntilFail = true;
+ this->Impl->RepeatUntilFail = true;
}
}
@@ -1838,21 +1879,21 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--no-compress-output")) {
- this->CompressTestOutput = false;
+ this->Impl->CompressTestOutput = false;
}
if (this->CheckArgument(arg, "--print-labels")) {
- this->PrintLabels = true;
+ this->Impl->PrintLabels = true;
}
if (this->CheckArgument(arg, "--http1.0")) {
- this->UseHTTP10 = true;
+ this->Impl->UseHTTP10 = true;
}
if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
i++;
auto timeout = cmDuration(atof(args[i].c_str()));
- this->GlobalTimeout = timeout;
+ this->Impl->GlobalTimeout = timeout;
}
if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
@@ -1867,47 +1908,44 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--debug")) {
- this->Debug = true;
- this->ShowLineNumbers = true;
+ this->Impl->Debug = true;
+ this->Impl->ShowLineNumbers = true;
}
if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
i++;
- this->SpecificTrack = args[i];
+ this->Impl->SpecificTrack = args[i];
}
if (this->CheckArgument(arg, "--show-line-numbers")) {
- this->ShowLineNumbers = true;
+ this->Impl->ShowLineNumbers = true;
}
if (this->CheckArgument(arg, "--no-label-summary")) {
- this->LabelSummary = false;
+ this->Impl->LabelSummary = false;
}
if (this->CheckArgument(arg, "--no-subproject-summary")) {
- this->SubprojectSummary = false;
+ this->Impl->SubprojectSummary = false;
}
if (this->CheckArgument(arg, "-Q", "--quiet")) {
- this->Quiet = true;
+ this->Impl->Quiet = true;
}
if (this->CheckArgument(arg, "--progress")) {
- this->TestProgressOutput = true;
+ this->Impl->TestProgressOutput = true;
}
if (this->CheckArgument(arg, "-V", "--verbose")) {
- this->Verbose = true;
+ this->Impl->Verbose = true;
}
if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
- this->ExtraVerbose = true;
- this->Verbose = true;
+ this->Impl->ExtraVerbose = true;
+ this->Impl->Verbose = true;
}
if (this->CheckArgument(arg, "--output-on-failure")) {
- this->OutputTestOutputOnTestFailure = true;
+ this->Impl->OutputTestOutputOnTestFailure = true;
}
if (this->CheckArgument(arg, "--test-output-size-passed") &&
i < args.size() - 1) {
i++;
long outputSize;
if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
- if (cmCTestTestHandler* pCTestTestHandler =
- static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
- pCTestTestHandler->SetTestOutputSizePassed(int(outputSize));
- }
+ this->Impl->TestHandler.SetTestOutputSizePassed(int(outputSize));
} else {
cmCTestLog(this, WARNING,
"Invalid value for '--test-output-size-passed': " << args[i]
@@ -1919,10 +1957,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
i++;
long outputSize;
if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
- if (cmCTestTestHandler* pCTestTestHandler =
- static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
- pCTestTestHandler->SetTestOutputSizeFailed(int(outputSize));
- }
+ this->Impl->TestHandler.SetTestOutputSizeFailed(int(outputSize));
} else {
cmCTestLog(this, WARNING,
"Invalid value for '--test-output-size-failed': " << args[i]
@@ -1930,10 +1965,10 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
}
if (this->CheckArgument(arg, "-N", "--show-only")) {
- this->ShowOnly = true;
+ this->Impl->ShowOnly = true;
}
if (cmSystemTools::StringStartsWith(arg.c_str(), "--show-only=")) {
- this->ShowOnly = true;
+ this->Impl->ShowOnly = true;
// Check if a specific format is requested. Defaults to human readable
// text.
@@ -1941,9 +1976,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
std::string format = arg.substr(argWithFormat.length());
if (format == "json-v1") {
// Force quiet mode so the only output is the json object model.
- this->Quiet = true;
- this->OutputAsJson = true;
- this->OutputAsJsonVersion = 1;
+ this->Impl->Quiet = true;
+ this->Impl->OutputAsJson = true;
+ this->Impl->OutputAsJsonVersion = 1;
} else if (format != "human") {
errormsg = "'--show-only=' given unknown value '" + format + "'";
return false;
@@ -1956,25 +1991,25 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--tomorrow-tag")) {
- this->TomorrowTag = true;
+ this->Impl->TomorrowTag = true;
}
if (this->CheckArgument(arg, "--force-new-ctest-process")) {
- this->ForceNewCTestProcess = true;
+ this->Impl->ForceNewCTestProcess = true;
}
if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
i++;
- this->MaxTestNameWidth = atoi(args[i].c_str());
+ this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
}
if (this->CheckArgument(arg, "--interactive-debug-mode") &&
i < args.size() - 1) {
i++;
- this->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
+ this->Impl->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
}
if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) {
i++;
- this->SubmitIndex = atoi(args[i].c_str());
- if (this->SubmitIndex < 0) {
- this->SubmitIndex = 0;
+ this->Impl->SubmitIndex = atoi(args[i].c_str());
+ if (this->Impl->SubmitIndex < 0) {
+ this->Impl->SubmitIndex = 0;
}
}
@@ -1983,7 +2018,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
this->AddCTestConfigurationOverwrite(args[i]);
}
if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
this->SetTest("Notes");
i++;
this->SetNotesFiles(args[i].c_str());
@@ -1993,78 +2028,75 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
if (this->CheckArgument(arg, "-I", "--tests-information") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("TestsToRunInformation", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-U", "--union")) {
- this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
- this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
+ this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
}
if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("IncludeRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("IncludeRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("LabelRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("LabelRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeLabelRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeLabelRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
}
if (this->CheckArgument(arg, "-E", "--exclude-regex") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("ExcludeRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureSetupRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureSetupRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureCleanupRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureCleanupRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "--rerun-failed")) {
- this->GetHandler("test")->SetPersistentOption("RerunFailed", "true");
- this->GetHandler("memcheck")->SetPersistentOption("RerunFailed", "true");
+ this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
}
return true;
}
@@ -2111,10 +2143,9 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
std::string arg = args[i];
if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
i < args.size() - 1) {
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
// -SR is an internal argument, -SP should be ignored when it is passed
if (!SRArgumentSpecified) {
ch->AddConfigurationScript(args[i].c_str(), false);
@@ -2123,18 +2154,16 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
SRArgumentSpecified = true;
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
ch->AddConfigurationScript(args[i].c_str(), true);
}
if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
// -SR is an internal argument, -S should be ignored when it is passed
if (!SRArgumentSpecified) {
ch->AddConfigurationScript(args[i].c_str(), true);
@@ -2149,7 +2178,7 @@ bool cmCTest::AddVariableDefinition(const std::string& arg)
cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
if (cmake::ParseCacheEntry(arg, name, value, type)) {
- this->Definitions[name] = value;
+ this->Impl->Definitions[name] = value;
return true;
}
@@ -2165,8 +2194,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
bool SRArgumentSpecified = false;
// copy the command line
- this->InitialCommandLineArguments.insert(
- this->InitialCommandLineArguments.end(), args.begin(), args.end());
+ cmAppend(this->Impl->InitialCommandLineArguments, args);
// process the command line arguments
for (size_t i = 1; i < args.size(); ++i) {
@@ -2183,7 +2211,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --dashboard: handle a request for a dashboard
std::string arg = args[i];
if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
i++;
std::string targ = args[i];
// AddTestsForDashboard parses the dashboard type and converts it
@@ -2219,7 +2247,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --extra-submit
if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
this->SetTest("Submit");
i++;
if (!this->SubmitExtraFiles(args[i].c_str())) {
@@ -2234,14 +2262,14 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --schedule-random
if (this->CheckArgument(arg, "--schedule-random")) {
- this->ScheduleType = "Random";
+ this->Impl->ScheduleType = "Random";
}
// pass the argument to all the handlers as well, but i may no longer be
// set to what it was originally so I'm not sure this is working as
// intended
- for (auto& handler : this->TestingHandlers) {
- if (!handler.second->ProcessCommandLineArguments(arg, i, args)) {
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ if (!handler->ProcessCommandLineArguments(arg, i, args)) {
cmCTestLog(this, ERROR_MESSAGE,
"Problem parsing command line arguments within a handler");
return 0;
@@ -2250,7 +2278,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
} // the close of the for argument loop
// handle CTEST_PARALLEL_LEVEL environment variable
- if (!this->ParallelLevelSetInCli) {
+ if (!this->Impl->ParallelLevelSetInCli) {
std::string parallel;
if (cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL", parallel)) {
int plevel = atoi(parallel.c_str());
@@ -2260,10 +2288,10 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// TestProgressOutput only supported if console supports it and not logging
// to a file
- this->TestProgressOutput = this->TestProgressOutput &&
- !this->OutputLogFile && this->ProgressOutputSupportedByConsole();
+ this->Impl->TestProgressOutput = this->Impl->TestProgressOutput &&
+ !this->Impl->OutputLogFile && this->ProgressOutputSupportedByConsole();
#ifdef _WIN32
- if (this->TestProgressOutput) {
+ if (this->Impl->TestProgressOutput) {
// Disable output line buffering so we can print content without
// a newline.
std::setvbuf(stdout, nullptr, _IONBF, 0);
@@ -2290,7 +2318,7 @@ bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i,
std::string arg = args[i];
if (this->CheckArgument(arg, "-T", "--test-action") &&
(i < args.size() - 1)) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
i++;
if (!this->SetTest(args[i].c_str(), false)) {
success = false;
@@ -2350,16 +2378,16 @@ int cmCTest::ExecuteTests()
{
int res;
// call process directory
- if (this->RunConfigurationScript) {
- if (this->ExtraVerbose) {
+ if (this->Impl->RunConfigurationScript) {
+ if (this->Impl->ExtraVerbose) {
cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
}
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetVerbose(this->ExtraVerbose);
- handler.second->SetSubmitIndex(this->SubmitIndex);
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->ExtraVerbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
}
- this->GetHandler("script")->SetVerbose(this->Verbose);
- res = this->GetHandler("script")->ProcessHandler();
+ this->GetScriptHandler()->SetVerbose(this->Impl->Verbose);
+ res = this->GetScriptHandler()->ProcessHandler();
if (res != 0) {
cmCTestLog(this, DEBUG,
"running script failing returning: " << res << std::endl);
@@ -2368,11 +2396,11 @@ int cmCTest::ExecuteTests()
} else {
// What is this? -V seems to be the same as -VV,
// and Verbose is always on in this case
- this->ExtraVerbose = this->Verbose;
- this->Verbose = true;
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetVerbose(this->Verbose);
- handler.second->SetSubmitIndex(this->SubmitIndex);
+ this->Impl->ExtraVerbose = this->Impl->Verbose;
+ this->Impl->Verbose = true;
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->Verbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
}
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
if (!this->Initialize(cwd.c_str(), nullptr)) {
@@ -2393,9 +2421,8 @@ int cmCTest::ExecuteTests()
int cmCTest::RunCMakeAndTest(std::string* output)
{
- this->Verbose = true;
- cmCTestBuildAndTestHandler* handler =
- static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
+ this->Impl->Verbose = true;
+ cmCTestBuildAndTestHandler* handler = this->GetBuildAndTestHandler();
int retv = handler->ProcessHandler();
*output = handler->GetOutput();
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -2413,7 +2440,12 @@ void cmCTest::SetNotesFiles(const char* notes)
if (!notes) {
return;
}
- this->NotesFiles = notes;
+ this->Impl->NotesFiles = notes;
+}
+
+std::chrono::system_clock::time_point cmCTest::GetStopTime() const
+{
+ return this->Impl->StopTime;
}
void cmCTest::SetStopTime(std::string const& time_str)
@@ -2443,21 +2475,29 @@ void cmCTest::SetStopTime(std::string const& time_str)
time_t stop_time = curl_getdate(buf, &current_time);
if (stop_time == -1) {
- this->StopTime = std::chrono::system_clock::time_point();
+ this->Impl->StopTime = std::chrono::system_clock::time_point();
return;
}
- this->StopTime = std::chrono::system_clock::from_time_t(stop_time);
+ this->Impl->StopTime = std::chrono::system_clock::from_time_t(stop_time);
if (stop_time < current_time) {
- this->StopTime += std::chrono::hours(24);
+ this->Impl->StopTime += std::chrono::hours(24);
}
}
+std::string cmCTest::GetScheduleType() const
+{
+ return this->Impl->ScheduleType;
+}
+
+void cmCTest::SetScheduleType(std::string const& type)
+{
+ this->Impl->ScheduleType = type;
+}
+
int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
{
bool found = false;
- VectorOfStrings dirs;
- VectorOfStrings ndirs;
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration directory: " << dir
<< std::endl);
@@ -2505,7 +2545,7 @@ int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
}
if (found) {
- for (auto& handler : this->TestingHandlers) {
+ for (auto& handler : this->Impl->GetNamedTestingHandlers()) {
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration vectors for handler: "
<< handler.first << " (" << handler.second << ")"
@@ -2596,16 +2636,16 @@ std::string cmCTest::GetShortPathToFile(const char* cfname)
std::string cmCTest::GetCTestConfiguration(const std::string& name)
{
- if (this->CTestConfigurationOverwrites.find(name) !=
- this->CTestConfigurationOverwrites.end()) {
- return this->CTestConfigurationOverwrites[name];
+ if (this->Impl->CTestConfigurationOverwrites.find(name) !=
+ this->Impl->CTestConfigurationOverwrites.end()) {
+ return this->Impl->CTestConfigurationOverwrites[name];
}
- return this->CTestConfiguration[name];
+ return this->Impl->CTestConfiguration[name];
}
void cmCTest::EmptyCTestConfiguration()
{
- this->CTestConfiguration.clear();
+ this->Impl->CTestConfiguration.clear();
}
void cmCTest::SetCTestConfiguration(const char* name, const char* value,
@@ -2620,10 +2660,10 @@ void cmCTest::SetCTestConfiguration(const char* name, const char* value,
return;
}
if (!value) {
- this->CTestConfiguration.erase(name);
+ this->Impl->CTestConfiguration.erase(name);
return;
}
- this->CTestConfiguration[name] = value;
+ this->Impl->CTestConfiguration[name] = value;
}
std::string cmCTest::GetSubmitURL()
@@ -2654,69 +2694,190 @@ std::string cmCTest::GetSubmitURL()
std::string cmCTest::GetCurrentTag()
{
- return this->CurrentTag;
+ return this->Impl->CurrentTag;
}
std::string cmCTest::GetBinaryDir()
{
- return this->BinaryDir;
+ return this->Impl->BinaryDir;
}
std::string const& cmCTest::GetConfigType()
{
- return this->ConfigType;
+ return this->Impl->ConfigType;
+}
+
+cmDuration cmCTest::GetTimeOut() const
+{
+ return this->Impl->TimeOut;
+}
+
+void cmCTest::SetTimeOut(cmDuration t)
+{
+ this->Impl->TimeOut = t;
+}
+
+cmDuration cmCTest::GetGlobalTimeout() const
+{
+ return this->Impl->GlobalTimeout;
}
bool cmCTest::GetShowOnly()
{
- return this->ShowOnly;
+ return this->Impl->ShowOnly;
}
bool cmCTest::GetOutputAsJson()
{
- return this->OutputAsJson;
+ return this->Impl->OutputAsJson;
}
int cmCTest::GetOutputAsJsonVersion()
{
- return this->OutputAsJsonVersion;
+ return this->Impl->OutputAsJsonVersion;
+}
+
+bool cmCTest::ShouldUseHTTP10() const
+{
+ return this->Impl->UseHTTP10;
+}
+
+bool cmCTest::ShouldPrintLabels() const
+{
+ return this->Impl->PrintLabels;
}
int cmCTest::GetMaxTestNameWidth() const
{
- return this->MaxTestNameWidth;
+ return this->Impl->MaxTestNameWidth;
+}
+
+void cmCTest::SetMaxTestNameWidth(int w)
+{
+ this->Impl->MaxTestNameWidth = w;
}
void cmCTest::SetProduceXML(bool v)
{
- this->ProduceXML = v;
+ this->Impl->ProduceXML = v;
}
bool cmCTest::GetProduceXML()
{
- return this->ProduceXML;
+ return this->Impl->ProduceXML;
+}
+
+std::vector<std::string>& cmCTest::GetInitialCommandLineArguments()
+{
+ return this->Impl->InitialCommandLineArguments;
}
const char* cmCTest::GetSpecificTrack()
{
- if (this->SpecificTrack.empty()) {
+ if (this->Impl->SpecificTrack.empty()) {
return nullptr;
}
- return this->SpecificTrack.c_str();
+ return this->Impl->SpecificTrack.c_str();
}
void cmCTest::SetSpecificTrack(const char* track)
{
if (!track) {
- this->SpecificTrack.clear();
+ this->Impl->SpecificTrack.clear();
return;
}
- this->SpecificTrack = track;
+ this->Impl->SpecificTrack = track;
+}
+
+void cmCTest::SetFailover(bool failover)
+{
+ this->Impl->Failover = failover;
+}
+
+bool cmCTest::GetFailover() const
+{
+ return this->Impl->Failover;
+}
+
+bool cmCTest::GetTestProgressOutput() const
+{
+ return this->Impl->TestProgressOutput;
+}
+
+bool cmCTest::GetVerbose() const
+{
+ return this->Impl->Verbose;
+}
+
+bool cmCTest::GetExtraVerbose() const
+{
+ return this->Impl->ExtraVerbose;
+}
+
+void cmCTest::SetStreams(std::ostream* out, std::ostream* err)
+{
+ this->Impl->StreamOut = out;
+ this->Impl->StreamErr = err;
+}
+
+bool cmCTest::GetLabelSummary() const
+{
+ return this->Impl->LabelSummary;
+}
+
+bool cmCTest::GetSubprojectSummary() const
+{
+ return this->Impl->SubprojectSummary;
+}
+
+bool cmCTest::GetOutputTestOutputOnTestFailure() const
+{
+ return this->Impl->OutputTestOutputOnTestFailure;
+}
+
+const std::map<std::string, std::string>& cmCTest::GetDefinitions() const
+{
+ return this->Impl->Definitions;
+}
+
+int cmCTest::GetTestRepeat() const
+{
+ return this->Impl->RepeatTests;
+}
+
+bool cmCTest::GetRepeatUntilFail() const
+{
+ return this->Impl->RepeatUntilFail;
+}
+
+void cmCTest::SetBuildID(const std::string& id)
+{
+ this->Impl->BuildID = id;
+}
+
+std::string cmCTest::GetBuildID() const
+{
+ return this->Impl->BuildID;
}
void cmCTest::AddSubmitFile(Part part, const char* name)
{
- this->Parts[part].SubmitFiles.emplace_back(name);
+ this->Impl->Parts[part].SubmitFiles.emplace_back(name);
+}
+
+std::vector<std::string> const& cmCTest::GetSubmitFiles(Part part) const
+{
+ return this->Impl->Parts[part].SubmitFiles;
+}
+
+void cmCTest::ClearSubmitFiles(Part part)
+{
+ this->Impl->Parts[part].SubmitFiles.clear();
+}
+
+void cmCTest::SetSuppressUpdatingCTestConfiguration(bool val)
+{
+ this->Impl->SuppressUpdatingCTestConfiguration = val;
}
void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
@@ -2732,14 +2893,14 @@ void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
}
std::string key = overStr.substr(0, epos);
std::string value = overStr.substr(epos + 1);
- this->CTestConfigurationOverwrites[key] = value;
+ this->Impl->CTestConfigurationOverwrites[key] = value;
}
void cmCTest::SetConfigType(const char* ct)
{
- this->ConfigType = ct ? ct : "";
- cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
- std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
+ this->Impl->ConfigType = ct ? ct : "";
+ cmSystemTools::ReplaceString(this->Impl->ConfigType, ".\\", "");
+ std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->Impl->ConfigType;
cmSystemTools::PutEnv(confTypeEnv);
}
@@ -2776,7 +2937,7 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
stdErr->clear();
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -2796,21 +2957,21 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
switch (res) {
case cmsysProcess_Pipe_STDOUT:
- tempOutput.insert(tempOutput.end(), data, data + length);
+ cmAppend(tempOutput, data, data + length);
break;
case cmsysProcess_Pipe_STDERR:
- tempError.insert(tempError.end(), data, data + length);
+ cmAppend(tempError, data, data + length);
break;
default:
done = true;
}
if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
- this->ExtraVerbose) {
+ this->Impl->ExtraVerbose) {
processOutput.DecodeText(data, length, strdata);
cmSystemTools::Stdout(strdata);
}
}
- if (this->ExtraVerbose) {
+ if (this->Impl->ExtraVerbose) {
processOutput.DecodeText(std::string(), strdata);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
@@ -2820,11 +2981,11 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
cmsysProcess_WaitForExit(cp, nullptr);
if (!tempOutput.empty()) {
processOutput.DecodeText(tempOutput, tempOutput);
- stdOut->append(&*tempOutput.begin(), tempOutput.size());
+ stdOut->append(tempOutput.data(), tempOutput.size());
}
if (!tempError.empty()) {
processOutput.DecodeText(tempError, tempError);
- stdErr->append(&*tempError.begin(), tempError.size());
+ stdErr->append(tempError.data(), tempError.size());
}
bool result = true;
@@ -2859,12 +3020,12 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
void cmCTest::SetOutputLogFileName(const char* name)
{
- if (this->OutputLogFile) {
- delete this->OutputLogFile;
- this->OutputLogFile = nullptr;
+ if (this->Impl->OutputLogFile) {
+ delete this->Impl->OutputLogFile;
+ this->Impl->OutputLogFile = nullptr;
}
if (name) {
- this->OutputLogFile = new cmGeneratedFileStream(name);
+ this->Impl->OutputLogFile = new cmGeneratedFileStream(name);
}
}
@@ -2880,18 +3041,11 @@ static const char* cmCTestStringLogType[] = { "DEBUG",
#define cmCTestLogOutputFileLine(stream) \
do { \
- if (this->ShowLineNumbers) { \
+ if (this->Impl->ShowLineNumbers) { \
(stream) << std::endl << file << ":" << line << " "; \
} \
} while (false)
-void cmCTest::InitStreams()
-{
- // By default we write output to the process output streams.
- this->StreamOut = &std::cout;
- this->StreamErr = &std::cerr;
-}
-
void cmCTest::Log(int logType, const char* file, int line, const char* msg,
bool suppress)
{
@@ -2902,53 +3056,53 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
return;
}
if (logType == cmCTest::HANDLER_PROGRESS_OUTPUT &&
- (this->Debug || this->ExtraVerbose)) {
+ (this->Impl->Debug || this->Impl->ExtraVerbose)) {
return;
}
- if (this->OutputLogFile) {
+ if (this->Impl->OutputLogFile) {
bool display = true;
- if (logType == cmCTest::DEBUG && !this->Debug) {
+ if (logType == cmCTest::DEBUG && !this->Impl->Debug) {
display = false;
}
- if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
- !this->ExtraVerbose) {
+ if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Impl->Debug &&
+ !this->Impl->ExtraVerbose) {
display = false;
}
if (display) {
- cmCTestLogOutputFileLine(*this->OutputLogFile);
- if (logType != this->OutputLogFileLastTag) {
- *this->OutputLogFile << "[";
+ cmCTestLogOutputFileLine(*this->Impl->OutputLogFile);
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << "[";
if (logType >= OTHER || logType < 0) {
- *this->OutputLogFile << "OTHER";
+ *this->Impl->OutputLogFile << "OTHER";
} else {
- *this->OutputLogFile << cmCTestStringLogType[logType];
+ *this->Impl->OutputLogFile << cmCTestStringLogType[logType];
}
- *this->OutputLogFile << "] " << std::endl << std::flush;
+ *this->Impl->OutputLogFile << "] " << std::endl << std::flush;
}
- *this->OutputLogFile << msg << std::flush;
- if (logType != this->OutputLogFileLastTag) {
- *this->OutputLogFile << std::endl << std::flush;
- this->OutputLogFileLastTag = logType;
+ *this->Impl->OutputLogFile << msg << std::flush;
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << std::endl << std::flush;
+ this->Impl->OutputLogFileLastTag = logType;
}
}
}
- if (!this->Quiet) {
- std::ostream& out = *this->StreamOut;
- std::ostream& err = *this->StreamErr;
+ if (!this->Impl->Quiet) {
+ std::ostream& out = *this->Impl->StreamOut;
+ std::ostream& err = *this->Impl->StreamErr;
if (logType == HANDLER_TEST_PROGRESS_OUTPUT) {
- if (this->TestProgressOutput) {
+ if (this->Impl->TestProgressOutput) {
cmCTestLogOutputFileLine(out);
- if (this->FlushTestProgressLine) {
+ if (this->Impl->FlushTestProgressLine) {
printf("\r");
- this->FlushTestProgressLine = false;
+ this->Impl->FlushTestProgressLine = false;
out.flush();
}
std::string msg_str{ msg };
auto const lineBreakIt = msg_str.find('\n');
if (lineBreakIt != std::string::npos) {
- this->FlushTestProgressLine = true;
+ this->Impl->FlushTestProgressLine = true;
msg_str.erase(std::remove(msg_str.begin(), msg_str.end(), '\n'),
msg_str.end());
}
@@ -2965,7 +3119,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
switch (logType) {
case DEBUG:
- if (this->Debug) {
+ if (this->Impl->Debug) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
@@ -2973,14 +3127,14 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
break;
case OUTPUT:
case HANDLER_OUTPUT:
- if (this->Debug || this->Verbose) {
+ if (this->Impl->Debug || this->Impl->Verbose) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
}
break;
case HANDLER_VERBOSE_OUTPUT:
- if (this->Debug || this->ExtraVerbose) {
+ if (this->Impl->Debug || this->Impl->ExtraVerbose) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
@@ -3007,7 +3161,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
std::string cmCTest::GetColorCode(Color color) const
{
- if (this->OutputColorCode) {
+ if (this->Impl->OutputColorCode) {
#if defined(_WIN32)
// Not supported on Windows
static_cast<void>(color);
@@ -3021,14 +3175,7 @@ std::string cmCTest::GetColorCode(Color color) const
cmDuration cmCTest::GetRemainingTimeAllowed()
{
- if (!this->GetHandler("script")) {
- return cmCTest::MaxDuration();
- }
-
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
- return ch->GetRemainingTimeAllowed();
+ return this->GetScriptHandler()->GetRemainingTimeAllowed();
}
cmDuration cmCTest::MaxDuration()
@@ -3038,17 +3185,14 @@ cmDuration cmCTest::MaxDuration()
void cmCTest::SetRunCurrentScript(bool value)
{
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
- ch->SetRunCurrentScript(value);
+ this->GetScriptHandler()->SetRunCurrentScript(value);
}
void cmCTest::OutputTestErrors(std::vector<char> const& process_output)
{
std::string test_outputs("\n*** Test Failed:\n");
if (!process_output.empty()) {
- test_outputs.append(&*process_output.begin(), process_output.size());
+ test_outputs.append(process_output.data(), process_output.size());
}
cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 92a02c316..d300c33fa 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -10,13 +10,22 @@
#include <chrono>
#include <map>
-#include <set>
+#include <memory> // IWYU pragma: keep
#include <sstream>
#include <string>
#include <time.h>
#include <vector>
-class cmCTestGenericHandler;
+class cmCTestBuildHandler;
+class cmCTestBuildAndTestHandler;
+class cmCTestCoverageHandler;
+class cmCTestScriptHandler;
+class cmCTestTestHandler;
+class cmCTestUpdateHandler;
+class cmCTestConfigureHandler;
+class cmCTestMemCheckHandler;
+class cmCTestSubmitHandler;
+class cmCTestUploadHandler;
class cmCTestStartCommand;
class cmGeneratedFileStream;
class cmMakefile;
@@ -31,9 +40,6 @@ class cmXMLWriter;
*/
class cmCTest
{
- friend class cmCTestRunTest;
- friend class cmCTestMultiProcessHandler;
-
public:
typedef cmProcessOutput::Encoding Encoding;
/** Enumerate parts of the testing and submission process. */
@@ -54,44 +60,10 @@ public:
PartCount // Update names in constructor when adding a part
};
- /** Representation of one part. */
- struct PartInfo
- {
- void SetName(const std::string& name) { this->Name = name; }
- const std::string& GetName() const { return this->Name; }
-
- void Enable() { this->Enabled = true; }
- explicit operator bool() const { return this->Enabled; }
-
- std::vector<std::string> SubmitFiles;
-
- private:
- bool Enabled = false;
- std::string Name;
- };
-#ifdef CMAKE_BUILD_WITH_CMAKE
- enum HTTPMethod
- {
- HTTP_GET,
- HTTP_POST,
- HTTP_PUT
- };
-
- /**
- * Perform an HTTP request.
- */
- static int HTTPRequest(std::string url, HTTPMethod method,
- std::string& response, std::string const& fields = "",
- std::string const& putFile = "", int timeout = 0);
-#endif
-
/** Get a testing part id from its string name. Returns PartCount
if the string does not name a valid part. */
Part GetPartFromName(const char* name);
- typedef std::vector<std::string> VectorOfStrings;
- typedef std::set<std::string> SetOfStrings;
-
/** Process Command line arguments */
int Run(std::vector<std::string>&, std::string* output = nullptr);
@@ -128,7 +100,7 @@ public:
/**
* Is the tomorrow tag set?
*/
- bool GetTomorrowTag() { return this->TomorrowTag; }
+ bool GetTomorrowTag() const;
/**
* Try to run tests of the project
@@ -137,16 +109,16 @@ public:
/** what is the configuration type, e.g. Debug, Release etc. */
std::string const& GetConfigType();
- cmDuration GetTimeOut() { return this->TimeOut; }
- void SetTimeOut(cmDuration t) { this->TimeOut = t; }
+ cmDuration GetTimeOut() const;
+ void SetTimeOut(cmDuration t);
- cmDuration GetGlobalTimeout() { return this->GlobalTimeout; }
+ cmDuration GetGlobalTimeout() const;
/** how many test to run at the same time */
- int GetParallelLevel() { return this->ParallelLevel; }
+ int GetParallelLevel() const;
void SetParallelLevel(int);
- unsigned long GetTestLoad() { return this->TestLoad; }
+ unsigned long GetTestLoad() const;
void SetTestLoad(unsigned long);
/**
@@ -164,7 +136,7 @@ public:
* Set the cmake test mode (experimental, nightly, continuous).
*/
void SetTestModel(int mode);
- int GetTestModel() { return this->TestModel; }
+ int GetTestModel() const;
std::string GetTestModelString();
static int GetTestModelFromString(const char* str);
@@ -182,6 +154,9 @@ public:
cmCTest();
~cmCTest();
+ cmCTest(const cmCTest&) = delete;
+ cmCTest& operator=(const cmCTest&) = delete;
+
/** Set the notes files to be created. */
void SetNotesFiles(const char* notes);
@@ -219,26 +194,23 @@ public:
int GetOutputAsJsonVersion();
- bool ShouldUseHTTP10() { return this->UseHTTP10; }
+ bool ShouldUseHTTP10() const;
- bool ShouldPrintLabels() { return this->PrintLabels; }
+ bool ShouldPrintLabels() const;
bool ShouldCompressTestOutput();
bool CompressString(std::string& str);
- std::chrono::system_clock::time_point GetStopTime()
- {
- return this->StopTime;
- }
+ std::chrono::system_clock::time_point GetStopTime() const;
void SetStopTime(std::string const& time);
/** Used for parallel ctest job scheduling */
- std::string GetScheduleType() { return this->ScheduleType; }
- void SetScheduleType(std::string const& type) { this->ScheduleType = type; }
+ std::string GetScheduleType() const;
+ void SetScheduleType(std::string const& type);
/** The max output width */
int GetMaxTestNameWidth() const;
- void SetMaxTestNameWidth(int w) { this->MaxTestNameWidth = w; }
+ void SetMaxTestNameWidth(int w);
/**
* Run a single executable command and put the stdout and stderr
@@ -277,8 +249,9 @@ public:
* Run command specialized for make and configure. Returns process status
* and retVal is return value or exception.
*/
- int RunMakeCommand(const char* command, std::string& output, int* retVal,
- const char* dir, cmDuration timeout, std::ostream& ofs,
+ int RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs,
Encoding encoding = cmProcessOutput::Auto);
/** Return the current tag */
@@ -331,16 +304,18 @@ public:
Encoding encoding = cmProcessOutput::Auto);
/**
- * Execute handler and return its result. If the handler fails, it returns
- * negative value.
- */
- int ExecuteHandler(const char* handler);
-
- /**
* Get the handler object
*/
- cmCTestGenericHandler* GetHandler(const char* handler);
- cmCTestGenericHandler* GetInitializedHandler(const char* handler);
+ cmCTestBuildHandler* GetBuildHandler();
+ cmCTestBuildAndTestHandler* GetBuildAndTestHandler();
+ cmCTestCoverageHandler* GetCoverageHandler();
+ cmCTestScriptHandler* GetScriptHandler();
+ cmCTestTestHandler* GetTestHandler();
+ cmCTestUpdateHandler* GetUpdateHandler();
+ cmCTestConfigureHandler* GetConfigureHandler();
+ cmCTestMemCheckHandler* GetMemCheckHandler();
+ cmCTestSubmitHandler* GetSubmitHandler();
+ cmCTestUploadHandler* GetUploadHandler();
/**
* Set the CTest variable from CMake variable
@@ -350,9 +325,6 @@ public:
const std::string& cmake_var,
bool suppress = false);
- /** Make string safe to be sent as a URL */
- static std::string MakeURLSafe(const std::string&);
-
/** Decode a URL to the original string. */
static std::string DecodeURL(const std::string&);
@@ -360,10 +332,7 @@ public:
* Should ctect configuration be updated. When using new style ctest
* script, this should be true.
*/
- void SetSuppressUpdatingCTestConfiguration(bool val)
- {
- this->SuppressUpdatingCTestConfiguration = val;
- }
+ void SetSuppressUpdatingCTestConfiguration(bool val);
/**
* Add overwrite to ctest configuration.
@@ -373,14 +342,14 @@ public:
void AddCTestConfigurationOverwrite(const std::string& encstr);
/** Create XML file that contains all the notes specified */
- int GenerateNotesFile(const VectorOfStrings& files);
+ int GenerateNotesFile(std::vector<std::string> const& files);
/** Create XML file to indicate that build is complete */
int GenerateDoneFile();
/** Submit extra files to the server */
bool SubmitExtraFiles(const char* files);
- bool SubmitExtraFiles(const VectorOfStrings& files);
+ bool SubmitExtraFiles(std::vector<std::string> const& files);
/** Set the output log file name */
void SetOutputLogFileName(const char* name);
@@ -420,62 +389,52 @@ public:
std::string GetColorCode(Color color) const;
/** The Build ID is assigned by CDash */
- void SetBuildID(const std::string& id) { this->BuildID = id; }
- std::string GetBuildID() { return this->BuildID; }
+ void SetBuildID(const std::string& id);
+ std::string GetBuildID() const;
/** Add file to be submitted */
void AddSubmitFile(Part part, const char* name);
- std::vector<std::string> const& GetSubmitFiles(Part part)
- {
- return this->Parts[part].SubmitFiles;
- }
- void ClearSubmitFiles(Part part) { this->Parts[part].SubmitFiles.clear(); }
+ std::vector<std::string> const& GetSubmitFiles(Part part) const;
+ void ClearSubmitFiles(Part part);
/**
* Read the custom configuration files and apply them to the current ctest
*/
int ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf);
- std::vector<std::string>& GetInitialCommandLineArguments()
- {
- return this->InitialCommandLineArguments;
- }
+ std::vector<std::string>& GetInitialCommandLineArguments();
/** Set the track to submit to */
void SetSpecificTrack(const char* track);
const char* GetSpecificTrack();
- void SetFailover(bool failover) { this->Failover = failover; }
- bool GetFailover() { return this->Failover; }
+ void SetFailover(bool failover);
+ bool GetFailover() const;
- bool GetTestProgressOutput() const { return this->TestProgressOutput; }
+ bool GetTestProgressOutput() const;
- bool GetVerbose() { return this->Verbose; }
- bool GetExtraVerbose() { return this->ExtraVerbose; }
+ bool GetVerbose() const;
+ bool GetExtraVerbose() const;
/** Direct process output to given streams. */
- void SetStreams(std::ostream* out, std::ostream* err)
- {
- this->StreamOut = out;
- this->StreamErr = err;
- }
+ void SetStreams(std::ostream* out, std::ostream* err);
+
void AddSiteProperties(cmXMLWriter& xml);
- bool GetLabelSummary() { return this->LabelSummary; }
- bool GetSubprojectSummary() { return this->SubprojectSummary; }
+ bool GetLabelSummary() const;
+ bool GetSubprojectSummary() const;
std::string GetCostDataFile();
- const std::map<std::string, std::string>& GetDefinitions()
- {
- return this->Definitions;
- }
+ bool GetOutputTestOutputOnTestFailure() const;
+
+ const std::map<std::string, std::string>& GetDefinitions() const;
/** Return the number of times a test should be run */
- int GetTestRepeat() { return this->RepeatTests; }
+ int GetTestRepeat() const;
/** Return true if test should run until fail */
- bool GetRepeatUntilFail() { return this->RepeatUntilFail; }
+ bool GetRepeatUntilFail() const;
void GenerateSubprojectsOutput(cmXMLWriter& xml);
std::vector<std::string> GetLabelsForSubprojects();
@@ -483,85 +442,8 @@ public:
void SetRunCurrentScript(bool value);
private:
- int RepeatTests;
- bool RepeatUntilFail;
- std::string ConfigType;
- std::string ScheduleType;
- std::chrono::system_clock::time_point StopTime;
- bool TestProgressOutput;
- bool Verbose;
- bool ExtraVerbose;
- bool ProduceXML;
- bool LabelSummary;
- bool SubprojectSummary;
- bool UseHTTP10;
- bool PrintLabels;
- bool Failover;
-
- bool FlushTestProgressLine;
-
- bool ForceNewCTestProcess;
-
- bool RunConfigurationScript;
-
int GenerateNotesFile(const char* files);
- // these are helper classes
- typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers;
- t_TestingHandlers TestingHandlers;
-
- bool ShowOnly;
- bool OutputAsJson;
- int OutputAsJsonVersion;
-
- /** Map of configuration properties */
- typedef std::map<std::string, std::string> CTestConfigurationMap;
-
- // TODO: The ctest configuration should be a hierarchy of
- // configuration option sources: command-line, script, ini file.
- // Then the ini file can get re-loaded whenever it changes without
- // affecting any higher-precedence settings.
- CTestConfigurationMap CTestConfiguration;
- CTestConfigurationMap CTestConfigurationOverwrites;
- PartInfo Parts[PartCount];
- typedef std::map<std::string, Part> PartMapType;
- PartMapType PartMap;
-
- std::string CurrentTag;
- bool TomorrowTag;
-
- int TestModel;
- std::string SpecificTrack;
-
- cmDuration TimeOut;
-
- cmDuration GlobalTimeout;
-
- int MaxTestNameWidth;
-
- int ParallelLevel;
- bool ParallelLevelSetInCli;
-
- unsigned long TestLoad;
-
- int CompatibilityMode;
-
- // information for the --build-and-test options
- std::string BinaryDir;
-
- std::string NotesFiles;
-
- bool InteractiveDebugMode;
-
- bool ShortDateFormat;
-
- bool CompressXMLFiles;
- bool CompressTestOutput;
-
- void InitStreams();
- std::ostream* StreamOut;
- std::ostream* StreamErr;
-
void BlockTestErrorDiagnostics();
/**
@@ -606,7 +488,8 @@ private:
bool UpdateCTestConfiguration();
/** Create note from files. */
- int GenerateCTestNotesOutput(cmXMLWriter& xml, const VectorOfStrings& files);
+ int GenerateCTestNotesOutput(cmXMLWriter& xml,
+ std::vector<std::string> const& files);
/** Check if the argument is the one specified */
bool CheckArgument(const std::string& arg, const char* varg1,
@@ -626,25 +509,8 @@ private:
int RunCMakeAndTest(std::string* output);
int ExecuteTests();
- bool SuppressUpdatingCTestConfiguration;
-
- bool Debug;
- bool ShowLineNumbers;
- bool Quiet;
-
- std::string BuildID;
-
- std::vector<std::string> InitialCommandLineArguments;
-
- int SubmitIndex;
-
- cmGeneratedFileStream* OutputLogFile;
- int OutputLogFileLastTag;
-
- bool OutputTestOutputOnTestFailure;
- bool OutputColorCode;
-
- std::map<std::string, std::string> Definitions;
+ struct Private;
+ std::unique_ptr<Private> Impl;
};
class cmCTestLogWrite
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 2728f0f9a..358f095bb 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -239,8 +239,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
cmGeneratedFileStream fout(cacheFile);
fout.SetCopyIfDifferent(true);
if (!fout) {
- cmSystemTools::Error("Unable to open cache file for save. ",
- cacheFile.c_str());
+ cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
cmSystemTools::ReportLastSystemError("");
return false;
}
@@ -309,8 +308,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
if (!ce.Initialized) {
/*
// This should be added in, but is not for now.
- cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
- "\" is uninitialized");
+ cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
*/
} else if (t != cmStateEnums::INTERNAL) {
// Format is key:type=value
@@ -364,8 +362,8 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
checkCacheFile += "/cmake.check_cache";
cmsys::ofstream checkCache(checkCacheFile.c_str());
if (!checkCache) {
- cmSystemTools::Error("Unable to open check cache file for write. ",
- checkCacheFile.c_str());
+ cmSystemTools::Error("Unable to open check cache file for write. " +
+ checkCacheFile);
return false;
}
checkCache << "# This file is generated by cmake for dependency checking "
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index 0c70ed27f..65f22f72b 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -93,33 +93,33 @@ public:
CacheEntry& GetEntry() { return this->Position->second; }
};
- ///! return an iterator to iterate through the cache map
+ //! return an iterator to iterate through the cache map
cmCacheManager::CacheIterator NewIterator() { return CacheIterator(*this); }
- ///! Load a cache for given makefile. Loads from path/CMakeCache.txt.
+ //! Load a cache for given makefile. Loads from path/CMakeCache.txt.
bool LoadCache(const std::string& path, bool internal,
std::set<std::string>& excludes,
std::set<std::string>& includes);
- ///! Save cache for given makefile. Saves to output path/CMakeCache.txt
+ //! Save cache for given makefile. Saves to output path/CMakeCache.txt
bool SaveCache(const std::string& path, cmMessenger* messenger);
- ///! Delete the cache given
+ //! Delete the cache given
bool DeleteCache(const std::string& path);
- ///! Print the cache to a stream
+ //! Print the cache to a stream
void PrintCache(std::ostream&) const;
- ///! Get the iterator for an entry with a given key.
+ //! Get the iterator for an entry with a given key.
cmCacheManager::CacheIterator GetCacheIterator(const char* key = nullptr);
- ///! Remove an entry from the cache
+ //! Remove an entry from the cache
void RemoveCacheEntry(const std::string& key);
- ///! Get the number of entries in the cache
+ //! Get the number of entries in the cache
int GetSize() { return static_cast<int>(this->Cache.size()); }
- ///! Get a value from the cache given a key
+ //! Get a value from the cache given a key
const std::string* GetInitializedCacheValue(const std::string& key) const;
const char* GetCacheEntryValue(const std::string& key)
@@ -197,14 +197,14 @@ public:
unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; }
protected:
- ///! Add an entry into the cache
+ //! Add an entry into the cache
void AddCacheEntry(const std::string& key, const char* value,
const char* helpString,
cmStateEnums::CacheEntryType type);
- ///! Get a cache entry object for a key
+ //! Get a cache entry object for a key
CacheEntry* GetCacheEntry(const std::string& key);
- ///! Clean out the CMakeFiles directory if no CMakeCache.txt
+ //! Clean out the CMakeFiles directory if no CMakeCache.txt
void CleanCMakeFiles(const std::string& path);
// Cache version info
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
index ee5feee76..f7a224492 100644
--- a/Source/cmCallVisualStudioMacro.cxx
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -35,8 +35,8 @@ static bool LogErrorsAsMessages;
# endif
# endif
-///! Use ReportHRESULT to make a cmSystemTools::Message after calling
-///! a COM method that may have failed.
+//! Use ReportHRESULT to make a cmSystemTools::Message after calling
+//! a COM method that may have failed.
# define ReportHRESULT(hr, context) \
if (FAILED(hr)) { \
if (LogErrorsAsMessages) { \
@@ -50,7 +50,7 @@ static bool LogErrorsAsMessages;
} \
}
-///! Using the given instance of Visual Studio, call the named macro
+//! Using the given instance of Visual Studio, call the named macro
HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
const std::string& args)
{
@@ -61,7 +61,8 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
if (0 != vsIDE) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"ExecuteCommand";
+ wchar_t execute_command[] = L"ExecuteCommand";
+ OLECHAR* name = execute_command;
hr =
vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
@@ -119,7 +120,8 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
}
oss << " dwHelpContext: " << excep.dwHelpContext << std::endl;
oss << " pvReserved: " << excep.pvReserved << std::endl;
- oss << " pfnDeferredFillIn: " << excep.pfnDeferredFillIn << std::endl;
+ oss << " pfnDeferredFillIn: "
+ << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << std::endl;
oss << " scode: " << excep.scode << std::endl;
}
@@ -133,14 +135,15 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
return hr;
}
-///! Get the Solution object from the IDE object
+//! Get the Solution object from the IDE object
HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
{
HRESULT hr = E_POINTER;
if (0 != vsIDE) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"Solution";
+ wchar_t solution[] = L"Solution";
+ OLECHAR* name = solution;
hr =
vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
@@ -176,14 +179,15 @@ HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
return hr;
}
-///! Get the FullName property from the Solution object
+//! Get the FullName property from the Solution object
HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
{
HRESULT hr = E_POINTER;
if (0 != vsSolution) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"FullName";
+ wchar_t full_name[] = L"FullName";
+ OLECHAR* name = full_name;
hr = vsSolution->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT,
&dispid);
@@ -220,7 +224,7 @@ HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
return hr;
}
-///! Get the FullName property from the Solution object, given the IDE object
+//! Get the FullName property from the Solution object, given the IDE object
HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
{
IDispatchPtr vsSolution;
@@ -235,8 +239,8 @@ HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
return hr;
}
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
{
// mrot == Map of the Running Object Table
@@ -292,8 +296,8 @@ HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
return hr;
}
-///! Do the two file names refer to the same Visual Studio solution? Or are
-///! we perhaps looking for any and all solutions?
+//! Do the two file names refer to the same Visual Studio solution? Or are
+//! we perhaps looking for any and all solutions?
bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
{
if (slnFile == "ALL" || slnName == "ALL") {
@@ -310,9 +314,9 @@ bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
return s1 == s2;
}
-///! Find instances of Visual Studio with the given solution file
-///! open. Pass "ALL" for slnFile to gather all running instances
-///! of Visual Studio.
+//! Find instances of Visual Studio with the given solution file
+//! open. Pass "ALL" for slnFile to gather all running instances
+//! of Visual Studio.
HRESULT FindVisualStudioInstances(const std::string& slnFile,
std::vector<IDispatchPtr>& instances)
{
@@ -384,8 +388,8 @@ int cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
return count;
}
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
int cmCallVisualStudioMacro::CallMacro(const std::string& slnFile,
const std::string& macro,
const std::string& args,
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
index fdc9e6646..9b5b3a843 100644
--- a/Source/cmCallVisualStudioMacro.h
+++ b/Source/cmCallVisualStudioMacro.h
@@ -16,16 +16,16 @@
class cmCallVisualStudioMacro
{
public:
- ///! Call the named macro in instances of Visual Studio with the
- ///! given solution file open. Pass "ALL" for slnFile to call the
- ///! macro in each Visual Studio instance.
+ //! Call the named macro in instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to call the
+ //! macro in each Visual Studio instance.
static int CallMacro(const std::string& slnFile, const std::string& macro,
const std::string& args,
const bool logErrorsAsMessages);
- ///! Count the number of running instances of Visual Studio with the
- ///! given solution file open. Pass "ALL" for slnFile to count all
- ///! running Visual Studio instances.
+ //! Count the number of running instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to count all
+ //! running Visual Studio instances.
static int GetNumberOfRunningVisualStudioInstances(
const std::string& slnFile);
diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx
deleted file mode 100644
index 968b17cb9..000000000
--- a/Source/cmCommandArgumentsHelper.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCommandArgumentsHelper.h"
-
-cmCommandArgument::cmCommandArgument(cmCommandArgumentsHelper* args,
- const char* key,
- cmCommandArgumentGroup* group)
- : Key(key)
- , Group(group)
- , WasActive(false)
- , ArgumentsBeforeEmpty(true)
- , CurrentIndex(0)
-{
- if (args != nullptr) {
- args->AddArgument(this);
- }
-
- if (this->Group != nullptr) {
- this->Group->ContainedArguments.push_back(this);
- }
-}
-
-void cmCommandArgument::Reset()
-{
- this->WasActive = false;
- this->CurrentIndex = 0;
- this->DoReset();
-}
-
-void cmCommandArgument::Follows(const cmCommandArgument* arg)
-{
- this->ArgumentsBeforeEmpty = false;
- this->ArgumentsBefore.insert(arg);
-}
-
-void cmCommandArgument::FollowsGroup(const cmCommandArgumentGroup* group)
-{
- if (group != nullptr) {
- this->ArgumentsBeforeEmpty = false;
- this->ArgumentsBefore.insert(group->ContainedArguments.begin(),
- group->ContainedArguments.end());
- }
-}
-
-bool cmCommandArgument::MayFollow(const cmCommandArgument* current) const
-{
- if (this->ArgumentsBeforeEmpty) {
- return true;
- }
- return this->ArgumentsBefore.find(current) != this->ArgumentsBefore.end();
-}
-
-bool cmCommandArgument::KeyMatches(const std::string& key) const
-{
- if ((this->Key == nullptr) || (this->Key[0] == '\0')) {
- return true;
- }
- return (key == this->Key);
-}
-
-void cmCommandArgument::ApplyOwnGroup()
-{
- if (this->Group != nullptr) {
- for (cmCommandArgument* cargs : this->Group->ContainedArguments) {
- if (cargs != this) {
- this->ArgumentsBefore.insert(cargs);
- }
- }
- }
-}
-
-void cmCommandArgument::Activate()
-{
- this->WasActive = true;
- this->CurrentIndex = 0;
-}
-
-bool cmCommandArgument::Consume(const std::string& arg)
-{
- bool res = this->DoConsume(arg, this->CurrentIndex);
- this->CurrentIndex++;
- return res;
-}
-
-cmCAStringVector::cmCAStringVector(cmCommandArgumentsHelper* args,
- const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Ignore(nullptr)
-{
- if ((key == nullptr) || (*key == 0)) {
- this->DataStart = 0;
- } else {
- this->DataStart = 1;
- }
-}
-
-bool cmCAStringVector::DoConsume(const std::string& arg, unsigned int index)
-{
- if (index >= this->DataStart) {
- if ((this->Ignore == nullptr) || (arg != this->Ignore)) {
- this->Vector.push_back(arg);
- }
- }
-
- return false;
-}
-
-void cmCAStringVector::DoReset()
-{
- this->Vector.clear();
-}
-
-cmCAString::cmCAString(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
-{
- if ((key == nullptr) || (*key == 0)) {
- this->DataStart = 0;
- } else {
- this->DataStart = 1;
- }
-}
-
-bool cmCAString::DoConsume(const std::string& arg, unsigned int index)
-{
- if (index == this->DataStart) {
- this->String = arg;
- }
-
- return index >= this->DataStart;
-}
-
-void cmCAString::DoReset()
-{
- this->String.clear();
-}
-
-cmCAEnabler::cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Enabled(false)
-{
-}
-
-bool cmCAEnabler::DoConsume(const std::string&, unsigned int index)
-{
- if (index == 0) {
- this->Enabled = true;
- }
- return true;
-}
-
-void cmCAEnabler::DoReset()
-{
- this->Enabled = false;
-}
-
-cmCADisabler::cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Enabled(true)
-{
-}
-
-bool cmCADisabler::DoConsume(const std::string&, unsigned int index)
-{
- if (index == 0) {
- this->Enabled = false;
- }
- return true;
-}
-
-void cmCADisabler::DoReset()
-{
- this->Enabled = true;
-}
-
-void cmCommandArgumentGroup::Follows(const cmCommandArgument* arg)
-{
- for (cmCommandArgument* ca : this->ContainedArguments) {
- ca->Follows(arg);
- }
-}
-
-void cmCommandArgumentGroup::FollowsGroup(const cmCommandArgumentGroup* group)
-{
- for (cmCommandArgument* ca : this->ContainedArguments) {
- ca->FollowsGroup(group);
- }
-}
-
-void cmCommandArgumentsHelper::Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs)
-{
- if (args == nullptr) {
- return;
- }
-
- for (cmCommandArgument* ca : this->Arguments) {
- ca->ApplyOwnGroup();
- ca->Reset();
- }
-
- cmCommandArgument* activeArgument = nullptr;
- const cmCommandArgument* previousArgument = nullptr;
- for (std::string const& it : *args) {
- for (cmCommandArgument* ca : this->Arguments) {
- if (ca->KeyMatches(it) && (ca->MayFollow(previousArgument))) {
- activeArgument = ca;
- activeArgument->Activate();
- break;
- }
- }
-
- if (activeArgument) {
- bool argDone = activeArgument->Consume(it);
- previousArgument = activeArgument;
- if (argDone) {
- activeArgument = nullptr;
- }
- } else {
- if (unconsumedArgs != nullptr) {
- unconsumedArgs->push_back(it);
- }
- }
- }
-}
-
-void cmCommandArgumentsHelper::AddArgument(cmCommandArgument* arg)
-{
- this->Arguments.push_back(arg);
-}
diff --git a/Source/cmCommandArgumentsHelper.h b/Source/cmCommandArgumentsHelper.h
deleted file mode 100644
index dc934bed6..000000000
--- a/Source/cmCommandArgumentsHelper.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmCommandArgumentsHelper_h
-#define cmCommandArgumentsHelper_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <set>
-#include <string>
-#include <vector>
-
-class cmCommandArgumentGroup;
-class cmCommandArgumentsHelper;
-
-/* cmCommandArgumentsHelper, cmCommandArgumentGroup and cmCommandArgument (i.e.
-its derived classes cmCAXXX can be used to simplify the processing of
-arguments to cmake commands. Maybe they can also be used to generate
-documentation.
-
-For every argument supported by a command one cmCommandArgument is created
-and added to cmCommandArgumentsHelper. cmCommand has a cmCommandArgumentsHelper
-as member variable so this should be used.
-
-The order of the arguments is defined using the Follows(arg) method. It says
-that this argument follows immediateley the given argument. It can be used
-with multiple arguments if the argument can follow after different arguments.
-
-Arguments can be arranged in groups using cmCommandArgumentGroup. Every
-member of a group can follow any other member of the group. These groups
-can also be used to define the order.
-
-Once all arguments and groups are set up, cmCommandArgumentsHelper::Parse()
-is called and afterwards the values of the arguments can be evaluated.
-
-For an example see cmExportCommand.cxx.
-*/
-class cmCommandArgument
-{
-public:
- cmCommandArgument(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
- virtual ~cmCommandArgument() = default;
-
- /// this argument may follow after arg. 0 means it comes first.
- void Follows(const cmCommandArgument* arg);
-
- /// this argument may follow after any of the arguments in the given group
- void FollowsGroup(const cmCommandArgumentGroup* group);
-
- /// Returns true if the argument was found in the argument list
- bool WasFound() const { return this->WasActive; }
-
- // The following methods are only called from
- // cmCommandArgumentsHelper::Parse(), but making this a friend would
- // give it access to everything
-
- /// Make the current argument the currently active argument
- void Activate();
- /// Consume the current string
- bool Consume(const std::string& arg);
-
- /// Return true if this argument may follow after the given argument.
- bool MayFollow(const cmCommandArgument* current) const;
-
- /** Returns true if the given key matches the key for this argument.
- If this argument has an empty key everything matches. */
- bool KeyMatches(const std::string& key) const;
-
- /// Make this argument follow all members of the own group
- void ApplyOwnGroup();
-
- /// Reset argument, so it's back to its initial state
- void Reset();
-
-private:
- const char* Key;
- std::set<const cmCommandArgument*> ArgumentsBefore;
- cmCommandArgumentGroup* Group;
- bool WasActive;
- bool ArgumentsBeforeEmpty;
- unsigned int CurrentIndex;
-
- virtual bool DoConsume(const std::string& arg, unsigned int index) = 0;
- virtual void DoReset() = 0;
-};
-
-/** cmCAStringVector is to be used for arguments which can consist of more
-than one string, e.g. the FILES argument in INSTALL(FILES f1 f2 f3 ...). */
-class cmCAStringVector : public cmCommandArgument
-{
-public:
- cmCAStringVector(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Return the vector of strings
- const std::vector<std::string>& GetVector() const { return this->Vector; }
-
- /** Is there a keyword which should be skipped in
- the arguments (e.g. ARGS for ADD_CUSTOM_COMMAND) ? */
- void SetIgnore(const char* ignore) { this->Ignore = ignore; }
-
-private:
- std::vector<std::string> Vector;
- unsigned int DataStart;
- const char* Ignore;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCAString is to be used for arguments which consist of one value,
-e.g. the executable name in ADD_EXECUTABLE(). */
-class cmCAString : public cmCommandArgument
-{
-public:
- cmCAString(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Return the string
- const std::string& GetString() const { return this->String; }
- const char* GetCString() const { return this->String.c_str(); }
-
-private:
- std::string String;
- unsigned int DataStart;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCAEnabler is to be used for options which are off by default and can be
-enabled using a special argument, e.g. EXCLUDE_FROM_ALL in ADD_EXECUTABLE(). */
-class cmCAEnabler : public cmCommandArgument
-{
-public:
- cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Has it been enabled ?
- bool IsEnabled() const { return this->Enabled; }
-
-private:
- bool Enabled;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCADisable is to be used for options which are on by default and can be
-disabled using a special argument.*/
-class cmCADisabler : public cmCommandArgument
-{
-public:
- cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Is it still enabled ?
- bool IsEnabled() const { return this->Enabled; }
-
-private:
- bool Enabled;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** Group of arguments, needed for ordering. E.g. WIN32, EXCLUDE_FROM_ALL and
-MACSOX_BUNDLE from ADD_EXECUTABLE() are a group.
-*/
-class cmCommandArgumentGroup
-{
- friend class cmCommandArgument;
-
-public:
- /// All members of this group may follow the given argument
- void Follows(const cmCommandArgument* arg);
-
- /// All members of this group may follow all members of the given group
- void FollowsGroup(const cmCommandArgumentGroup* group);
-
-private:
- std::vector<cmCommandArgument*> ContainedArguments;
-};
-
-class cmCommandArgumentsHelper
-{
-public:
- /// Parse the argument list
- void Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs);
- /// Add an argument.
- void AddArgument(cmCommandArgument* arg);
-
-private:
- std::vector<cmCommandArgument*> Arguments;
-};
-
-#endif
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 4717cf6b5..186deb60c 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -9,6 +9,7 @@
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
@@ -256,11 +257,7 @@ cmComputeLinkDepends::Compute()
// Iterate in reverse order so we can keep only the last occurrence
// of a shared library.
std::set<int> emmitted;
- for (std::vector<int>::const_reverse_iterator
- li = this->FinalLinkOrder.rbegin(),
- le = this->FinalLinkOrder.rend();
- li != le; ++li) {
- int i = *li;
+ for (int i : cmReverseRange(this->FinalLinkOrder)) {
LinkEntry const& e = this->EntryList[i];
cmGeneratorTarget const* t = e.Target;
// Entries that we know the linker will re-use do not need to be repeated.
@@ -586,11 +583,10 @@ void cmComputeLinkDepends::InferDependencies()
}
// Intersect the sets for this item.
- DependSetList::const_iterator i = sets->begin();
- DependSet common = *i;
- for (++i; i != sets->end(); ++i) {
+ DependSet common = sets->front();
+ for (DependSet const& i : cmMakeRange(*sets).advance(1)) {
DependSet intersection;
- std::set_intersection(common.begin(), common.end(), i->begin(), i->end(),
+ std::set_intersection(common.begin(), common.end(), i.begin(), i.end(),
std::inserter(intersection, intersection.begin()));
common = intersection;
}
@@ -708,9 +704,8 @@ void cmComputeLinkDepends::VisitComponent(unsigned int c)
// Run in reverse order so the topological order will preserve the
// original order where there are no constraints.
EdgeList const& nl = this->CCG->GetComponentGraphEdges(c);
- for (EdgeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
- ++ni) {
- this->VisitComponent(*ni);
+ for (cmGraphEdge const& edge : cmReverseRange(nl)) {
+ this->VisitComponent(edge);
}
// Assign an ordering id to this component.
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 252f8748c..dfaaf8b96 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -31,6 +31,9 @@ public:
const std::string& config);
~cmComputeLinkDepends();
+ cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
+ cmComputeLinkDepends& operator=(const cmComputeLinkDepends&) = delete;
+
// Basic information about each link item.
struct LinkEntry
{
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 3d61665fd..44d8615e0 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -457,8 +457,8 @@ bool cmComputeLinkInformation::Compute()
// We require a link language for the target.
if (this->LinkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Target->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ this->Target->GetName());
return false;
}
@@ -1266,7 +1266,7 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
{
if (this->Makefile->IsOn("APPLE") &&
- cmSystemTools::IsPathToFramework(item.c_str())) {
+ cmSystemTools::IsPathToFramework(item)) {
this->AddFrameworkItem(item);
} else {
this->DropDirectoryItem(item);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 9b7b02f53..01d4c07e0 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -11,6 +11,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -549,10 +550,9 @@ bool cmComputeTargetDepends::ComputeFinalDepends(
int head = -1;
std::set<int> emitted;
NodeList const& nl = components[c];
- for (NodeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
- ++ni) {
+ for (int ni : cmReverseRange(nl)) {
std::set<int> visited;
- if (!this->IntraComponent(cmap, c, *ni, &head, emitted, visited)) {
+ if (!this->IntraComponent(cmap, c, ni, &head, emitted, visited)) {
// Cycle in add_dependencies within component!
this->ComplainAboutBadComponent(ccg, c, true);
return false;
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 94ea529ea..e7e91c1a8 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -94,10 +94,7 @@ bool cmConditionEvaluator::IsTrue(
}
// store the reduced args in this vector
- cmArgumentList newArgs;
-
- // copy to the list structure
- newArgs.insert(newArgs.end(), args.begin(), args.end());
+ cmArgumentList newArgs(args.begin(), args.end());
// now loop through the arguments and see if we can reduce any of them
// we do this multiple times. Once for each level of precedence
@@ -130,8 +127,8 @@ bool cmConditionEvaluator::IsTrue(
return false;
}
- return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
- errorString, status, true);
+ return this->GetBooleanValueWithAutoDereference(newArgs.front(), errorString,
+ status, true);
}
//=========================================================================
@@ -398,7 +395,7 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
// copy to the list structure
cmArgumentList::iterator argP1 = arg;
argP1++;
- newArgs2.insert(newArgs2.end(), argP1, argClose);
+ cmAppend(newArgs2, argP1, argClose);
newArgs2.pop_back();
// now recursively invoke IsTrue to handle the values inside the
// parenthetical expression
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
index 8224a0fe3..0917d1102 100644
--- a/Source/cmConfigureFileCommand.cxx
+++ b/Source/cmConfigureFileCommand.cxx
@@ -102,7 +102,7 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args,
int cmConfigureFileCommand::ConfigureFile()
{
- return this->Makefile->ConfigureFile(
- this->InputFile.c_str(), this->OutputFile.c_str(), this->CopyOnly,
- this->AtOnly, this->EscapeQuotes, this->NewLineStyle);
+ return this->Makefile->ConfigureFile(this->InputFile, this->OutputFile,
+ this->CopyOnly, this->AtOnly,
+ this->EscapeQuotes, this->NewLineStyle);
}
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 037d4157a..f12ef0b4a 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -20,6 +20,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmVersion.h"
+#include "cm_static_string_view.hxx"
#include "cmake.h"
static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN =
@@ -42,6 +43,8 @@ static std::string const kCMAKE_LINK_SEARCH_END_STATIC =
"CMAKE_LINK_SEARCH_END_STATIC";
static std::string const kCMAKE_LINK_SEARCH_START_STATIC =
"CMAKE_LINK_SEARCH_START_STATIC";
+static std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT =
+ "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT";
static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
"CMAKE_OSX_DEPLOYMENT_TARGET";
@@ -60,7 +63,8 @@ static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
/* GHS Multi platform variables */
static std::set<std::string> ghs_platform_vars{
"GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
- "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME"
+ "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
+ "GHS_OS_DIR_OPTION"
};
static void writeProperty(FILE* fout, std::string const& targetName,
@@ -118,8 +122,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
- const char* sourceDirectory = argv[2].c_str();
- const char* projectName = nullptr;
+ std::string sourceDirectory = argv[2];
+ std::string projectName;
std::string targetName;
std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
std::vector<std::string> compileDefs;
@@ -305,7 +309,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
doing = DoingNone;
} else if (i == 3) {
this->SrcFileSignature = false;
- projectName = argv[i].c_str();
+ projectName = argv[i];
} else if (i == 4 && !this->SrcFileSignature) {
targetName = argv[i];
} else {
@@ -476,7 +480,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// we need to create a directory and CMakeLists file etc...
// first create the directories
- sourceDirectory = this->BinaryDirectory.c_str();
+ sourceDirectory = this->BinaryDirectory;
// now create a CMakeLists.txt file in that directory
FILE* fout = cmsys::SystemTools::Fopen(outFileName, "w");
@@ -499,6 +503,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def);
}
+ /* Set MSVC runtime library policy to match our selection. */
+ if (const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
+ fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
+ *msvcRuntimeLibraryDefault ? "NEW" : "OLD");
+ }
+
std::string projectLangs;
for (std::string const& li : testLangs) {
projectLangs += " " + li;
@@ -659,6 +670,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
vars.insert(kCMAKE_SYSROOT_COMPILE);
vars.insert(kCMAKE_SYSROOT_LINK);
vars.insert(kCMAKE_WARN_DEPRECATED);
+ vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
if (const char* varListStr = this->Makefile->GetDefinition(
kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
@@ -896,7 +908,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// Forward the GHS variables to the inner project cache.
for (std::string const& var : ghs_platform_vars) {
if (const char* val = this->Makefile->GetDefinition(var)) {
- std::string flag = "-D" + var + "=" + val;
+ std::string flag = "-D" + var + "=" + "'" + val + "'";
cmakeFlags.push_back(std::move(flag));
}
}
@@ -938,7 +950,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
<< " '" << copyFile << "'\n";
/* clang-format on */
if (!this->FindErrorMessage.empty()) {
- emsg << this->FindErrorMessage.c_str();
+ emsg << this->FindErrorMessage;
}
if (copyFileError.empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
@@ -965,8 +977,8 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
if (binDir.find("CMakeTmp") == std::string::npos) {
cmSystemTools::Error(
"TRY_COMPILE attempt to remove -rf directory that does not contain "
- "CMakeTmp:",
- binDir.c_str());
+ "CMakeTmp:" +
+ binDir);
return;
}
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 69532e61b..b78493f99 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -136,8 +136,7 @@ bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& args,
this->Makefile->AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES",
functionMapCode.c_str());
bool res = true;
- if (!this->Makefile->ConfigureFile(configFile.c_str(), driver.c_str(), false,
- true, false)) {
+ if (!this->Makefile->ConfigureFile(configFile, driver, false, true, false)) {
res = false;
}
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 242ceaab4..7402eeb37 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCustomCommand.h"
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include <utility>
@@ -54,13 +55,12 @@ const char* cmCustomCommand::GetComment() const
void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines)
{
- this->CommandLines.insert(this->CommandLines.end(), commandLines.begin(),
- commandLines.end());
+ cmAppend(this->CommandLines, commandLines);
}
void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends)
{
- this->Depends.insert(this->Depends.end(), depends.begin(), depends.end());
+ cmAppend(this->Depends, depends);
}
bool cmCustomCommand::GetEscapeOldStyle() const
@@ -101,8 +101,7 @@ void cmCustomCommand::SetImplicitDepends(ImplicitDependsList const& l)
void cmCustomCommand::AppendImplicitDepends(ImplicitDependsList const& l)
{
- this->ImplicitDepends.insert(this->ImplicitDepends.end(), l.begin(),
- l.end());
+ cmAppend(this->ImplicitDepends, l);
}
bool cmCustomCommand::GetUsesTerminal() const
@@ -134,3 +133,13 @@ void cmCustomCommand::SetDepfile(const std::string& depfile)
{
this->Depfile = depfile;
}
+
+const std::string& cmCustomCommand::GetJobPool() const
+{
+ return this->JobPool;
+}
+
+void cmCustomCommand::SetJobPool(const std::string& job_pool)
+{
+ this->JobPool = job_pool;
+}
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 50f15a46f..9a6f2390c 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -89,6 +89,10 @@ public:
const std::string& GetDepfile() const;
void SetDepfile(const std::string& depfile);
+ /** Set/Get the job_pool (used by the Ninja generator) */
+ const std::string& GetJobPool() const;
+ void SetJobPool(const std::string& job_pool);
+
private:
std::vector<std::string> Outputs;
std::vector<std::string> Byproducts;
@@ -99,6 +103,7 @@ private:
std::string Comment;
std::string WorkingDirectory;
std::string Depfile;
+ std::string JobPool;
bool HaveComment = false;
bool EscapeAllowMakeVars = false;
bool EscapeOldStyle = true;
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 6bf99468e..89aaad0dc 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCustomCommandGenerator.h"
+#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratorExpression.h"
@@ -33,9 +34,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
this->GE->Parse(clarg);
std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
if (this->CC.GetCommandExpandLists()) {
- std::vector<std::string> ExpandedArg;
- cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg);
- argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end());
+ cmAppend(argv, cmSystemTools::ExpandedListArgument(parsed_arg));
} else {
argv.push_back(std::move(parsed_arg));
}
@@ -54,15 +53,14 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
std::vector<std::string> depends = this->CC.GetDepends();
for (std::string const& d : depends) {
std::unique_ptr<cmCompiledGeneratorExpression> cge = this->GE->Parse(d);
- std::vector<std::string> result;
- cmSystemTools::ExpandListArgument(cge->Evaluate(this->LG, this->Config),
- result);
+ std::vector<std::string> result = cmSystemTools::ExpandedListArgument(
+ cge->Evaluate(this->LG, this->Config));
for (std::string& it : result) {
if (cmSystemTools::FileIsFullPath(it)) {
it = cmSystemTools::CollapseFullPath(it);
}
}
- this->Depends.insert(this->Depends.end(), result.begin(), result.end());
+ cmAppend(this->Depends, result);
}
const std::string& workingdirectory = this->CC.GetWorkingDirectory();
@@ -77,6 +75,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
}
}
+
+ this->FillEmulatorsWithArguments();
}
cmCustomCommandGenerator::~cmCustomCommandGenerator()
@@ -89,19 +89,38 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
return static_cast<unsigned int>(this->CC.GetCommandLines().size());
}
-const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
- unsigned int c) const
+void cmCustomCommandGenerator::FillEmulatorsWithArguments()
{
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
- return nullptr;
+ return;
}
- std::string const& argv0 = this->CommandLines[c][0];
- cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
- if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
- !target->IsImported()) {
- return target->GetProperty("CROSSCOMPILING_EMULATOR");
+
+ for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
+ std::string const& argv0 = this->CommandLines[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
+ !target->IsImported()) {
+
+ const char* emulator_property =
+ target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (!emulator_property) {
+ continue;
+ }
+
+ this->EmulatorsWithArguments.emplace_back();
+ cmSystemTools::ExpandListArgument(emulator_property,
+ this->EmulatorsWithArguments[c]);
+ }
}
- return nullptr;
+}
+
+std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
+ unsigned int c) const
+{
+ if (c >= this->EmulatorsWithArguments.size()) {
+ return std::vector<std::string>();
+ }
+ return this->EmulatorsWithArguments[c];
}
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
@@ -131,8 +150,9 @@ bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
{
- if (const char* emulator = this->GetCrossCompilingEmulator(c)) {
- return std::string(emulator);
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ return emulator[0];
}
if (const char* location = this->GetArgv0Location(c)) {
return std::string(location);
@@ -170,9 +190,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
std::string& cmd) const
{
unsigned int offset = 1;
- if (this->GetCrossCompilingEmulator(c) != nullptr) {
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ for (unsigned j = 1; j < emulator.size(); ++j) {
+ cmd += " ";
+ if (this->OldStyle) {
+ cmd += escapeForShellOldStyle(emulator[j]);
+ } else {
+ cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars);
+ }
+ }
+
offset = 0;
}
+
cmCustomCommandLine const& commandLine = this->CommandLines[c];
for (unsigned int j = offset; j < commandLine.size(); ++j) {
std::string arg;
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 9684cffa8..766f4b81d 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -22,16 +22,21 @@ class cmCustomCommandGenerator
bool MakeVars;
cmGeneratorExpression* GE;
cmCustomCommandLines CommandLines;
+ std::vector<std::vector<std::string>> EmulatorsWithArguments;
std::vector<std::string> Depends;
std::string WorkingDirectory;
- const char* GetCrossCompilingEmulator(unsigned int c) const;
+ void FillEmulatorsWithArguments();
+ std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const;
public:
cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
cmLocalGenerator* lg);
~cmCustomCommandGenerator();
+ cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
+ cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
+ delete;
cmCustomCommand const& GetCC() const { return this->CC; }
unsigned int GetNumberOfCommands() const;
std::string GetCommand(unsigned int c) const;
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
index 7d1d31624..ed76dbf47 100644
--- a/Source/cmDepends.cxx
+++ b/Source/cmDepends.cxx
@@ -2,7 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmDepends.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
@@ -10,46 +11,39 @@
#include "cmsys/FStream.hxx"
#include <sstream>
-#include <string.h>
#include <utility>
cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir)
: LocalGenerator(lg)
, TargetDirectory(std::move(targetDir))
- , Dependee(new char[MaxPath])
- , Depender(new char[MaxPath])
{
}
-cmDepends::~cmDepends()
-{
- delete[] this->Dependee;
- delete[] this->Depender;
-}
+cmDepends::~cmDepends() = default;
bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
{
- // Lookup the set of sources to scan.
- std::string srcLang = "CMAKE_DEPENDS_CHECK_";
- srcLang += this->Language;
- cmMakefile* mf = this->LocalGenerator->GetMakefile();
- std::string const& srcStr = mf->GetSafeDefinition(srcLang);
- std::vector<std::string> pairs;
- cmSystemTools::ExpandListArgument(srcStr, pairs);
-
std::map<std::string, std::set<std::string>> dependencies;
- for (std::vector<std::string>::iterator si = pairs.begin();
- si != pairs.end();) {
- // Get the source and object file.
- std::string const& src = *si++;
- if (si == pairs.end()) {
- break;
+ {
+ // Lookup the set of sources to scan.
+ std::vector<std::string> pairs;
+ {
+ std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ cmSystemTools::ExpandListArgument(mf->GetSafeDefinition(srcLang), pairs);
+ }
+ for (std::vector<std::string>::iterator si = pairs.begin();
+ si != pairs.end();) {
+ // Get the source and object file.
+ std::string const& src = *si++;
+ if (si == pairs.end()) {
+ break;
+ }
+ std::string const& obj = *si++;
+ dependencies[obj].insert(src);
}
- std::string const& obj = *si++;
- dependencies[obj].insert(src);
}
for (auto const& d : dependencies) {
-
// Write the dependencies for this pair.
if (!this->WriteDependencies(d.second, d.first, makeDepends,
internalDepends)) {
@@ -67,7 +61,7 @@ bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/)
bool cmDepends::Check(const std::string& makeFile,
const std::string& internalFile,
- std::map<std::string, DependencyVector>& validDeps)
+ DependencyMap& validDeps)
{
// Check whether dependencies must be regenerated.
bool okay = true;
@@ -76,9 +70,9 @@ bool cmDepends::Check(const std::string& makeFile,
// Clear all dependencies so they will be regenerated.
this->Clear(makeFile);
cmSystemTools::RemoveFile(internalFile);
+ this->FileTimeCache->Remove(internalFile);
okay = false;
}
-
return okay;
}
@@ -107,48 +101,62 @@ bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
return false;
}
-bool cmDepends::CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps)
+bool cmDepends::CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps)
{
+ // Read internal depends file time
+ cmFileTime internalDependsTime;
+ if (!this->FileTimeCache->Load(internalDependsFileName,
+ internalDependsTime)) {
+ return false;
+ }
+
// Parse dependencies from the stream. If any dependee is missing
// or newer than the depender then dependencies should be
// regenerated.
bool okay = true;
bool dependerExists = false;
- DependencyVector* currentDependencies = nullptr;
- while (internalDepends.getline(this->Dependee, this->MaxPath)) {
- if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
- this->Dependee[0] == '\r') {
+ std::string line;
+ line.reserve(1024);
+ std::string depender;
+ std::string dependee;
+ cmFileTime dependerTime;
+ cmFileTime dependeeTime;
+ std::vector<std::string>* currentDependencies = nullptr;
+
+ while (std::getline(internalDepends, line)) {
+ // Check if this an empty or a comment line
+ if (line.empty() || line.front() == '#') {
continue;
}
- size_t len = internalDepends.gcount() - 1;
- if (this->Dependee[len - 1] == '\r') {
- len--;
- this->Dependee[len] = 0;
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
}
- if (this->Dependee[0] != ' ') {
- memcpy(this->Depender, this->Dependee, len + 1);
- // Calling FileExists() for the depender here saves in many cases 50%
- // of the calls to FileExists() further down in the loop. E.g. for
- // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
- // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
- dependerExists = cmSystemTools::FileExists(this->Depender);
+ // Check if this a depender line
+ if (line.front() != ' ') {
+ depender = line;
+ dependerExists = this->FileTimeCache->Load(depender, dependerTime);
// If we erase validDeps[this->Depender] by overwriting it with an empty
// vector, we lose dependencies for dependers that have multiple
// entries. No need to initialize the entry, std::map will do so on first
// access.
- currentDependencies = &validDeps[this->Depender];
+ currentDependencies = &validDeps[depender];
continue;
}
- /*
- // Parse the dependency line.
- if(!this->ParseDependency(line.c_str()))
- {
- continue;
- }
- */
+
+ // This is a dependee line
+ dependee = line.substr(1);
+
+ // Add dependee to depender's list
+ if (currentDependencies != nullptr) {
+ currentDependencies->push_back(dependee);
+ }
// Dependencies must be regenerated
// * if the dependee does not exist
@@ -156,13 +164,8 @@ bool cmDepends::CheckDependencies(
// * if the depender does not exist, but the dependee is newer than the
// depends file
bool regenerate = false;
- const std::string dependee(this->Dependee + 1);
- const std::string depender(this->Depender);
- if (currentDependencies != nullptr) {
- currentDependencies->push_back(dependee);
- }
-
- if (!cmSystemTools::FileExists(dependee)) {
+ bool dependeeExists = this->FileTimeCache->Load(dependee, dependeeTime);
+ if (!dependeeExists) {
// The dependee does not exist.
regenerate = true;
@@ -173,45 +176,38 @@ bool cmDepends::CheckDependencies(
<< depender << "\"." << std::endl;
cmSystemTools::Stdout(msg.str());
}
- } else {
- if (dependerExists) {
- // The dependee and depender both exist. Compare file times.
- int result = 0;
- if ((!this->FileComparison->FileTimeCompare(depender, dependee,
- &result) ||
- result < 0)) {
- // The depender is older than the dependee.
- regenerate = true;
-
- // Print verbose output.
- if (this->Verbose) {
- std::ostringstream msg;
- msg << "Dependee \"" << dependee << "\" is newer than depender \""
- << depender << "\"." << std::endl;
- cmSystemTools::Stdout(msg.str());
- }
+ } else if (dependerExists) {
+ // The dependee and depender both exist. Compare file times.
+ if (dependerTime.Older(dependeeTime)) {
+ // The depender is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee << "\" is newer than depender \""
+ << depender << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str());
}
- } else {
- // The dependee exists, but the depender doesn't. Regenerate if the
- // internalDepends file is older than the dependee.
- int result = 0;
- if ((!this->FileComparison->FileTimeCompare(internalDependsFileName,
- dependee, &result) ||
- result < 0)) {
- // The depends-file is older than the dependee.
- regenerate = true;
-
- // Print verbose output.
- if (this->Verbose) {
- std::ostringstream msg;
- msg << "Dependee \"" << dependee
- << "\" is newer than depends file \""
- << internalDependsFileName << "\"." << std::endl;
- cmSystemTools::Stdout(msg.str());
- }
+ }
+ } else {
+ // The dependee exists, but the depender doesn't. Regenerate if the
+ // internalDepends file is older than the dependee.
+ if (internalDependsTime.Older(dependeeTime)) {
+ // The depends-file is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee
+ << "\" is newer than depends file \"" << internalDependsFileName
+ << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str());
}
}
}
+
if (regenerate) {
// Dependencies must be regenerated.
okay = false;
@@ -219,13 +215,14 @@ bool cmDepends::CheckDependencies(
// Remove the information of this depender from the map, it needs
// to be rescanned
if (currentDependencies != nullptr) {
- validDeps.erase(this->Depender);
+ validDeps.erase(depender);
currentDependencies = nullptr;
}
// Remove the depender to be sure it is rebuilt.
if (dependerExists) {
cmSystemTools::RemoveFile(depender);
+ this->FileTimeCache->Remove(depender);
dependerExists = false;
}
}
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
index 20c91ca57..b7475f0ae 100644
--- a/Source/cmDepends.h
+++ b/Source/cmDepends.h
@@ -8,11 +8,10 @@
#include <iosfwd>
#include <map>
#include <set>
-#include <stddef.h>
#include <string>
#include <vector>
-class cmFileTimeComparison;
+class cmFileTimeCache;
class cmLocalGenerator;
/** \class cmDepends
@@ -25,6 +24,9 @@ class cmLocalGenerator;
class cmDepends
{
public:
+ typedef std::map<std::string, std::vector<std::string>> DependencyMap;
+
+public:
/** Instances need to know the build directory name and the relative
path from the build directory to the target file. */
cmDepends(cmLocalGenerator* lg = nullptr, std::string targetDir = "");
@@ -56,26 +58,19 @@ public:
/** Write dependencies for the target file. */
bool Write(std::ostream& makeDepends, std::ostream& internalDepends);
- class DependencyVector : public std::vector<std::string>
- {
- };
-
/** Check dependencies for the target file. Returns true if
dependencies are okay and false if they must be generated. If
they must be generated Clear has already been called to wipe out
the old dependencies.
Dependencies which are still valid will be stored in validDeps. */
bool Check(const std::string& makeFile, const std::string& internalFile,
- std::map<std::string, DependencyVector>& validDeps);
+ DependencyMap& validDeps);
/** Clear dependencies for the target file so they will be regenerated. */
void Clear(const std::string& file);
/** Set the file comparison object */
- void SetFileComparison(cmFileTimeComparison* fc)
- {
- this->FileComparison = fc;
- }
+ void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; }
protected:
// Write dependencies for the target file to the given stream.
@@ -88,9 +83,9 @@ protected:
// Check dependencies for the target file in the given stream.
// Return false if dependencies must be regenerated and true
// otherwise.
- virtual bool CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps);
+ virtual bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps);
// Finalize the dependency information for the target.
virtual bool Finalize(std::ostream& makeDepends,
@@ -101,17 +96,13 @@ protected:
// Flag for verbose output.
bool Verbose = false;
- cmFileTimeComparison* FileComparison = nullptr;
+ cmFileTimeCache* FileTimeCache = nullptr;
std::string Language;
// The full path to the target's build directory.
std::string TargetDirectory;
- size_t MaxPath = 16384;
- char* Dependee;
- char* Depender;
-
// The include file search path.
std::vector<std::string> IncludePath;
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index b1630f9ae..dc49c18f8 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -6,7 +6,7 @@
#include <utility>
#include "cmAlgorithms.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -21,9 +21,8 @@
cmDependsC::cmDependsC() = default;
-cmDependsC::cmDependsC(
- cmLocalGenerator* lg, const std::string& targetDir, const std::string& lang,
- const std::map<std::string, DependencyVector>* validDeps)
+cmDependsC::cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
+ const std::string& lang, const DependencyMap* validDeps)
: cmDepends(lg, targetDir)
, ValidDeps(validDeps)
{
@@ -102,8 +101,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
this->LocalGenerator->MaybeConvertToRelativePath(binDir, obj);
if (this->ValidDeps != nullptr) {
- std::map<std::string, DependencyVector>::const_iterator tmpIt =
- this->ValidDeps->find(obj_i);
+ auto const tmpIt = this->ValidDeps->find(obj_i);
if (tmpIt != this->ValidDeps->end()) {
dependencies.insert(tmpIt->second.begin(), tmpIt->second.end());
haveDeps = true;
@@ -123,12 +121,6 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
}
std::set<std::string> scanned;
-
- // Use reserve to allocate enough memory for tempPathStr
- // so that during the loops no memory is allocated or freed
- std::string tempPathStr;
- tempPathStr.reserve(4 * 1024);
-
while (!this->Unscanned.empty()) {
// Get the next file to scan.
UnscannedEntry current = this->Unscanned.front();
@@ -147,22 +139,21 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
// the source containing the include statement.
fullName = current.QuotedLocation;
} else {
- std::map<std::string, std::string>::iterator headerLocationIt =
+ auto headerLocationIt =
this->HeaderLocationCache.find(current.FileName);
if (headerLocationIt != this->HeaderLocationCache.end()) {
fullName = headerLocationIt->second;
} else {
- for (std::string const& i : this->IncludePath) {
+ for (std::string const& iPath : this->IncludePath) {
// Construct the name of the file as if it were in the current
// include directory. Avoid using a leading "./".
-
- tempPathStr =
- cmSystemTools::CollapseCombinedPath(i, current.FileName);
+ std::string tmpPath =
+ cmSystemTools::CollapseFullPath(current.FileName, iPath);
// Look for the file in this location.
- if (cmSystemTools::FileExists(tempPathStr, true)) {
- fullName = tempPathStr;
- HeaderLocationCache[current.FileName] = fullName;
+ if (cmSystemTools::FileExists(tmpPath, true)) {
+ fullName = tmpPath;
+ this->HeaderLocationCache[current.FileName] = std::move(tmpPath);
break;
}
}
@@ -173,8 +164,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
// regex.
if (fullName.empty() &&
this->IncludeRegexComplain.find(current.FileName)) {
- cmSystemTools::Error("Cannot find file \"", current.FileName.c_str(),
- "\".");
+ cmSystemTools::Error("Cannot find file \"" + current.FileName + "\".");
return false;
}
@@ -184,8 +174,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
scanned.insert(fullName);
// Check whether this file is already in the cache
- std::map<std::string, cmIncludeLines*>::iterator fileIt =
- this->FileCache.find(fullName);
+ auto fileIt = this->FileCache.find(fullName);
if (fileIt != this->FileCache.end()) {
fileIt->second->Used = true;
dependencies.insert(fullName);
@@ -257,6 +246,8 @@ void cmDependsC::ReadCacheFile()
cmIncludeLines* cacheEntry = nullptr;
bool haveFileName = false;
+ cmFileTime cacheFileTime;
+ bool const cacheFileTimeGood = cacheFileTime.Load(this->CacheFileName);
while (cmSystemTools::GetLineFromStream(fin, line)) {
if (line.empty()) {
cacheEntry = nullptr;
@@ -266,11 +257,12 @@ void cmDependsC::ReadCacheFile()
// the first line after an empty line is the name of the parsed file
if (!haveFileName) {
haveFileName = true;
- int newer = 0;
- cmFileTimeComparison comp;
- bool res = comp.FileTimeCompare(this->CacheFileName, line, &newer);
- if (res && newer == 1) // cache is newer than the parsed file
+ cmFileTime fileTime;
+ bool const res = cacheFileTimeGood && fileTime.Load(line);
+ bool const newer = res && cacheFileTime.Newer(fileTime);
+
+ if (res && newer) // cache is newer than the parsed file
{
cacheEntry = new cmIncludeLines;
this->FileCache[line] = cacheEntry;
@@ -368,7 +360,7 @@ void cmDependsC::Scan(std::istream& is, const std::string& directory,
// must check for the file in the directory containing the
// file we are scanning.
entry.QuotedLocation =
- cmSystemTools::CollapseCombinedPath(directory, entry.FileName);
+ cmSystemTools::CollapseFullPath(entry.FileName, directory);
}
// Queue the file if it has not yet been encountered and it
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
index eee5ae15c..3fc839e43 100644
--- a/Source/cmDependsC.h
+++ b/Source/cmDependsC.h
@@ -27,8 +27,7 @@ public:
relative path from the build directory to the target file. */
cmDependsC();
cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
- const std::string& lang,
- const std::map<std::string, DependencyVector>* validDeps);
+ const std::string& lang, const DependencyMap* validDeps);
/** Virtual destructor to cleanup subclasses properly. */
~cmDependsC() override;
@@ -81,7 +80,7 @@ public:
};
protected:
- const std::map<std::string, DependencyVector>* ValidDeps = nullptr;
+ const DependencyMap* ValidDeps = nullptr;
std::set<std::string> Encountered;
std::queue<UnscannedEntry> Unscanned;
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index 3f036a9de..178e18b5f 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -295,7 +295,7 @@ void cmDependsFortran::MatchRemoteModules(std::istream& fin,
// They do not include the ".mod" extension.
mod += ".mod";
}
- this->ConsiderModule(mod.c_str() + 1, stampDir);
+ this->ConsiderModule(mod.substr(1), stampDir);
}
} else if (line == "provides") {
doing_provides = true;
diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx
index 2485e15fd..b17b2ba74 100644
--- a/Source/cmDependsJava.cxx
+++ b/Source/cmDependsJava.cxx
@@ -24,8 +24,7 @@ bool cmDependsJava::WriteDependencies(const std::set<std::string>& sources,
bool cmDependsJava::CheckDependencies(
std::istream& /*internalDepends*/,
- const std::string& /*internalDependsFileName*/,
- std::map<std::string, DependencyVector>& /*validDeps*/)
+ const std::string& /*internalDependsFileName*/, DependencyMap& /*validDeps*/)
{
return true;
}
diff --git a/Source/cmDependsJava.h b/Source/cmDependsJava.h
index 109ef13d1..dd671a1b6 100644
--- a/Source/cmDependsJava.h
+++ b/Source/cmDependsJava.h
@@ -8,7 +8,6 @@
#include "cmDepends.h"
#include <iosfwd>
-#include <map>
#include <set>
#include <string>
@@ -33,9 +32,9 @@ protected:
bool WriteDependencies(const std::set<std::string>& sources,
const std::string& file, std::ostream& makeDepends,
std::ostream& internalDepends) override;
- bool CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps) override;
+ bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps) override;
};
#endif
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
index 792db48a4..12d875d6f 100644
--- a/Source/cmDependsJavaParserHelper.cxx
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -5,6 +5,7 @@
#include "cmDependsJavaLexer.h"
#include "cmSystemTools.h"
+#include "cm_string_view.hxx"
#include "cmsys/FStream.hxx"
#include <iostream>
#include <stdio.h>
@@ -298,14 +299,10 @@ void cmDependsJavaParserHelper::Error(const char* str)
unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos,
this->CurrentLine);
- int cc;
- std::cerr << "String: [";
- for (cc = 0;
- cc < 30 && *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
- cc++) {
- std::cerr << *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
- }
- std::cerr << "]" << std::endl;
+ std::cerr << "String: ["
+ << cm::string_view{ this->InputBuffer }.substr(
+ this->InputBufferPos, 30)
+ << "]" << std::endl;
}
void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h
index 0b445d924..a673b5bbb 100644
--- a/Source/cmDependsJavaParserHelper.h
+++ b/Source/cmDependsJavaParserHelper.h
@@ -24,6 +24,10 @@ public:
cmDependsJavaParserHelper();
~cmDependsJavaParserHelper();
+ cmDependsJavaParserHelper(const cmDependsJavaParserHelper&) = delete;
+ cmDependsJavaParserHelper& operator=(const cmDependsJavaParserHelper&) =
+ delete;
+
int ParseString(const char* str, int verb);
int ParseFile(const char* file);
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
index 7031b525d..19c7407b7 100644
--- a/Source/cmDocumentationSection.h
+++ b/Source/cmDocumentationSection.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include <string>
@@ -46,7 +47,7 @@ public:
}
void Append(const std::vector<cmDocumentationEntry>& entries)
{
- this->Entries.insert(this->Entries.end(), entries.begin(), entries.end());
+ cmAppend(this->Entries, entries);
}
/** Append an entry to this section using NULL terminated chars */
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 27f91317f..222646365 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmELF.h"
+#include "cmAlgorithms.h"
#include "cm_kwiml.h"
#include "cmsys/FStream.hxx"
#include <map>
@@ -572,7 +573,7 @@ std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
}
char* pdyn = reinterpret_cast<char*>(&dyn);
- result.insert(result.end(), pdyn, pdyn + sizeof(ELF_Dyn));
+ cmAppend(result, pdyn, pdyn + sizeof(ELF_Dyn));
}
return result;
diff --git a/Source/cmELF.h b/Source/cmELF.h
index c8a91e4ea..987f0c3a4 100644
--- a/Source/cmELF.h
+++ b/Source/cmELF.h
@@ -28,6 +28,9 @@ public:
/** Destruct. */
~cmELF();
+ cmELF(const cmELF&) = delete;
+ cmELF& operator=(const cmELF&) = delete;
+
/** Get the error message if any. */
std::string const& GetErrorMessage() const { return this->ErrorMessage; }
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 75a7786a4..4b559e71a 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -67,7 +67,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
std::string command;
if (!arguments.empty()) {
- command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
+ command = cmSystemTools::ConvertToRunCommandPath(args[0]);
command += " ";
command += arguments;
} else {
@@ -82,11 +82,11 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
bool result = true;
if (args.size() - count == 2) {
cmSystemTools::MakeDirectory(args[1]);
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
+ result = cmExecProgramCommand::RunCommand(command, output, retVal,
args[1].c_str(), verbose);
} else {
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
- nullptr, verbose);
+ result = cmExecProgramCommand::RunCommand(command, output, retVal, nullptr,
+ verbose);
}
if (!result) {
retVal = -1;
@@ -115,7 +115,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
return true;
}
-bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
+bool cmExecProgramCommand::RunCommand(std::string command, std::string& output,
int& retVal, const char* dir,
bool verbose, Encoding encoding)
{
@@ -128,12 +128,11 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
// try to find the program, and if the program can not be
// found use system to run the command as it must be a built in
// shell command like echo or dir
- int count = 0;
- std::string shortCmd;
- if (command[0] == '\"') {
+ if (!command.empty() && command[0] == '\"') {
// count the number of quotes
- for (const char* s = command; *s != 0; ++s) {
- if (*s == '\"') {
+ int count = 0;
+ for (char c : command) {
+ if (c == '\"') {
count++;
if (count > 2) {
break;
@@ -147,20 +146,21 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
if (count > 2) {
cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
if (quoted.find(command)) {
+ std::string shortCmd;
std::string cmd = quoted.match(1);
std::string args = quoted.match(2);
if (!cmSystemTools::FileExists(cmd)) {
shortCmd = cmd;
- } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
- cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
+ } else if (!cmSystemTools::GetShortPath(cmd, shortCmd)) {
+ cmSystemTools::Error("GetShortPath failed for " + cmd);
return false;
}
shortCmd += " ";
shortCmd += args;
- command = shortCmd.c_str();
+ command = shortCmd;
} else {
- cmSystemTools::Error("Could not parse command line with quotes ",
+ cmSystemTools::Error("Could not parse command line with quotes " +
command);
}
}
@@ -182,7 +182,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
}
cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
- const char* cmd[] = { command, 0 };
+ const char* cmd[] = { command.c_str(), nullptr };
cmsysProcess_SetCommand(cp, cmd);
#else
std::string commandInDir;
@@ -197,7 +197,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
# ifndef __VMS
commandInDir += " 2>&1";
# endif
- command = commandInDir.c_str();
+ command = commandInDir;
if (verbose) {
cmSystemTools::Stdout("running ");
cmSystemTools::Stdout(command);
@@ -205,7 +205,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
}
fflush(stdout);
fflush(stderr);
- const char* cmd[] = { "/bin/sh", "-c", command, nullptr };
+ const char* cmd[] = { "/bin/sh", "-c", command.c_str(), nullptr };
cmsysProcess_SetCommand(cp, cmd);
#endif
diff --git a/Source/cmExecProgramCommand.h b/Source/cmExecProgramCommand.h
index dc5da740d..ae0fa9b84 100644
--- a/Source/cmExecProgramCommand.h
+++ b/Source/cmExecProgramCommand.h
@@ -37,7 +37,7 @@ public:
cmExecutionStatus& status) override;
private:
- static bool RunCommand(const char* command, std::string& output, int& retVal,
+ static bool RunCommand(std::string command, std::string& output, int& retVal,
const char* directory = nullptr, bool verbose = true,
Encoding encoding = cmProcessOutput::Auto);
};
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 8c67cdb4e..494afbb55 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -2,13 +2,17 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExecuteProcessCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/Process.h"
+#include <algorithm>
#include <ctype.h> /* isspace */
-#include <sstream>
+#include <iostream>
#include <stdio.h>
#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmProcessOutput.h"
#include "cmSystemTools.h"
@@ -32,173 +36,108 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- std::vector<std::vector<const char*>> cmds;
- std::string arguments;
- bool doing_command = false;
- size_t command_index = 0;
- bool output_quiet = false;
- bool error_quiet = false;
- bool output_strip_trailing_whitespace = false;
- bool error_strip_trailing_whitespace = false;
- std::string timeout_string;
- std::string input_file;
- std::string output_file;
- std::string error_file;
- std::string output_variable;
- std::string error_variable;
- std::string result_variable;
- std::string results_variable;
- std::string working_directory;
- cmProcessOutput::Encoding encoding = cmProcessOutput::None;
- for (size_t i = 0; i < args.size(); ++i) {
- if (args[i] == "COMMAND") {
- doing_command = true;
- command_index = cmds.size();
- cmds.emplace_back();
- } else if (args[i] == "OUTPUT_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- output_variable = args[i];
- } else {
- this->SetError(" called with no value for OUTPUT_VARIABLE.");
- return false;
- }
- } else if (args[i] == "ERROR_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- error_variable = args[i];
- } else {
- this->SetError(" called with no value for ERROR_VARIABLE.");
- return false;
- }
- } else if (args[i] == "RESULT_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- result_variable = args[i];
- } else {
- this->SetError(" called with no value for RESULT_VARIABLE.");
- return false;
- }
- } else if (args[i] == "RESULTS_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- results_variable = args[i];
- } else {
- this->SetError(" called with no value for RESULTS_VARIABLE.");
- return false;
- }
- } else if (args[i] == "WORKING_DIRECTORY") {
- doing_command = false;
- if (++i < args.size()) {
- working_directory = args[i];
- } else {
- this->SetError(" called with no value for WORKING_DIRECTORY.");
- return false;
- }
- } else if (args[i] == "INPUT_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- input_file = args[i];
- } else {
- this->SetError(" called with no value for INPUT_FILE.");
- return false;
- }
- } else if (args[i] == "OUTPUT_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- output_file = args[i];
- } else {
- this->SetError(" called with no value for OUTPUT_FILE.");
- return false;
- }
- } else if (args[i] == "ERROR_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- error_file = args[i];
- } else {
- this->SetError(" called with no value for ERROR_FILE.");
- return false;
- }
- } else if (args[i] == "TIMEOUT") {
- doing_command = false;
- if (++i < args.size()) {
- timeout_string = args[i];
- } else {
- this->SetError(" called with no value for TIMEOUT.");
- return false;
- }
- } else if (args[i] == "OUTPUT_QUIET") {
- doing_command = false;
- output_quiet = true;
- } else if (args[i] == "ERROR_QUIET") {
- doing_command = false;
- error_quiet = true;
- } else if (args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE") {
- doing_command = false;
- output_strip_trailing_whitespace = true;
- } else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") {
- doing_command = false;
- error_strip_trailing_whitespace = true;
- } else if (args[i] == "ENCODING") {
- doing_command = false;
- if (++i < args.size()) {
- encoding = cmProcessOutput::FindEncoding(args[i]);
- } else {
- this->SetError(" called with no value for ENCODING.");
- return false;
- }
- } else if (doing_command) {
- cmds[command_index].push_back(args[i].c_str());
- } else {
- std::ostringstream e;
- e << " given unknown argument \"" << args[i] << "\".";
- this->SetError(e.str());
- return false;
- }
+
+ struct Arguments
+ {
+ std::vector<std::vector<std::string>> Commands;
+ std::string OutputVariable;
+ std::string ErrorVariable;
+ std::string ResultVariable;
+ std::string ResultsVariable;
+ std::string WorkingDirectory;
+ std::string InputFile;
+ std::string OutputFile;
+ std::string ErrorFile;
+ std::string Timeout;
+ std::string CommandEcho;
+ bool OutputQuiet = false;
+ bool ErrorQuiet = false;
+ bool OutputStripTrailingWhitespace = false;
+ bool ErrorStripTrailingWhitespace = false;
+ std::string Encoding;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("COMMAND"_s, &Arguments::Commands)
+ .Bind("COMMAND_ECHO"_s, &Arguments::CommandEcho)
+ .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
+ .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable)
+ .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable)
+ .Bind("RESULTS_VARIABLE"_s, &Arguments::ResultsVariable)
+ .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory)
+ .Bind("INPUT_FILE"_s, &Arguments::InputFile)
+ .Bind("OUTPUT_FILE"_s, &Arguments::OutputFile)
+ .Bind("ERROR_FILE"_s, &Arguments::ErrorFile)
+ .Bind("TIMEOUT"_s, &Arguments::Timeout)
+ .Bind("OUTPUT_QUIET"_s, &Arguments::OutputQuiet)
+ .Bind("ERROR_QUIET"_s, &Arguments::ErrorQuiet)
+ .Bind("OUTPUT_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::OutputStripTrailingWhitespace)
+ .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::ErrorStripTrailingWhitespace)
+ .Bind("ENCODING"_s, &Arguments::Encoding);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ if (!keywordsMissingValue.empty()) {
+ this->SetError(" called with no value for " +
+ keywordsMissingValue.front() + ".");
+ return false;
+ }
+ if (!unparsedArguments.empty()) {
+ this->SetError(" given unknown argument \"" + unparsedArguments.front() +
+ "\".");
+ return false;
}
- if (!this->Makefile->CanIWriteThisFile(output_file)) {
- std::string e = "attempted to output into a file: " + output_file +
- " into a source directory.";
- this->SetError(e);
+ if (!this->Makefile->CanIWriteThisFile(arguments.OutputFile)) {
+ this->SetError("attempted to output into a file: " + arguments.OutputFile +
+ " into a source directory.");
cmSystemTools::SetFatalErrorOccured();
return false;
}
// Check for commands given.
- if (cmds.empty()) {
+ if (arguments.Commands.empty()) {
this->SetError(" called with no COMMAND argument.");
return false;
}
- for (auto& cmd : cmds) {
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
if (cmd.empty()) {
this->SetError(" given COMMAND argument with no value.");
return false;
}
- // Add the null terminating pointer to the command argument list.
- cmd.push_back(nullptr);
}
// Parse the timeout string.
double timeout = -1;
- if (!timeout_string.empty()) {
- if (sscanf(timeout_string.c_str(), "%lg", &timeout) != 1) {
+ if (!arguments.Timeout.empty()) {
+ if (sscanf(arguments.Timeout.c_str(), "%lg", &timeout) != 1) {
this->SetError(" called with TIMEOUT value that could not be parsed.");
return false;
}
}
-
// Create a process instance.
- cmsysProcess* cp = cmsysProcess_New();
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ cmsysProcess* cp = cp_ptr.get();
// Set the command sequence.
- for (auto const& cmd : cmds) {
- cmsysProcess_AddCommand(cp, &*cmd.begin());
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
+ std::vector<const char*> argv(cmd.size() + 1);
+ std::transform(cmd.begin(), cmd.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_AddCommand(cp, argv.data());
}
// Set the process working directory.
- if (!working_directory.empty()) {
- cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
+ if (!arguments.WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
}
// Always hide the process window.
@@ -206,22 +145,24 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
// Check the output variables.
bool merge_output = false;
- if (!input_file.empty()) {
- cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
+ if (!arguments.InputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
+ arguments.InputFile.c_str());
}
- if (!output_file.empty()) {
+ if (!arguments.OutputFile.empty()) {
cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
- output_file.c_str());
+ arguments.OutputFile.c_str());
}
- if (!error_file.empty()) {
- if (error_file == output_file) {
+ if (!arguments.ErrorFile.empty()) {
+ if (arguments.ErrorFile == arguments.OutputFile) {
merge_output = true;
} else {
cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
- error_file.c_str());
+ arguments.ErrorFile.c_str());
}
}
- if (!output_variable.empty() && output_variable == error_variable) {
+ if (!arguments.OutputVariable.empty() &&
+ arguments.OutputVariable == arguments.ErrorVariable) {
merge_output = true;
}
if (merge_output) {
@@ -233,6 +174,51 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
cmsysProcess_SetTimeout(cp, timeout);
}
+ bool echo_stdout = false;
+ bool echo_stderr = false;
+ bool echo_output_from_variable = true;
+ std::string echo_output =
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTE_PROCESS_COMMAND_ECHO");
+ if (!arguments.CommandEcho.empty()) {
+ echo_output_from_variable = false;
+ echo_output = arguments.CommandEcho;
+ }
+
+ if (!echo_output.empty()) {
+ if (echo_output == "STDERR") {
+ echo_stderr = true;
+ } else if (echo_output == "STDOUT") {
+ echo_stdout = true;
+ } else if (echo_output != "NONE") {
+ std::string error;
+ if (echo_output_from_variable) {
+ error = "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to '";
+ } else {
+ error = " called with '";
+ }
+ error += echo_output;
+ error += "' expected STDERR|STDOUT|NONE";
+ if (!echo_output_from_variable) {
+ error += " for COMMAND_ECHO.";
+ }
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, error);
+ return true;
+ }
+ }
+ if (echo_stdout || echo_stderr) {
+ std::string command;
+ for (auto& cmd : arguments.Commands) {
+ command += "'";
+ command += cmJoin(cmd, "' '");
+ command += "'";
+ command += "\n";
+ }
+ if (echo_stdout) {
+ std::cout << command;
+ } else if (echo_stderr) {
+ std::cerr << command;
+ }
+ }
// Start the process.
cmsysProcess_Execute(cp);
@@ -242,19 +228,20 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
int length;
char* data;
int p;
- cmProcessOutput processOutput(encoding);
+ cmProcessOutput processOutput(
+ cmProcessOutput::FindEncoding(arguments.Encoding));
std::string strdata;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
// Put the output in the right place.
- if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
- if (output_variable.empty()) {
+ if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
+ if (arguments.OutputVariable.empty()) {
processOutput.DecodeText(data, length, strdata, 1);
cmSystemTools::Stdout(strdata);
} else {
cmExecuteProcessCommandAppend(tempOutput, data, length);
}
- } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) {
- if (error_variable.empty()) {
+ } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
+ if (arguments.ErrorVariable.empty()) {
processOutput.DecodeText(data, length, strdata, 2);
cmSystemTools::Stderr(strdata);
} else {
@@ -262,13 +249,13 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
}
}
}
- if (!output_quiet && output_variable.empty()) {
+ if (!arguments.OutputQuiet && arguments.OutputVariable.empty()) {
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
}
}
- if (!error_quiet && error_variable.empty()) {
+ if (!arguments.ErrorQuiet && arguments.ErrorVariable.empty()) {
processOutput.DecodeText(std::string(), strdata, 2);
if (!strdata.empty()) {
cmSystemTools::Stderr(strdata);
@@ -281,46 +268,49 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
processOutput.DecodeText(tempError, tempError);
// Fix the text in the output strings.
- cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace);
- cmExecuteProcessCommandFixText(tempError, error_strip_trailing_whitespace);
+ cmExecuteProcessCommandFixText(tempOutput,
+ arguments.OutputStripTrailingWhitespace);
+ cmExecuteProcessCommandFixText(tempError,
+ arguments.ErrorStripTrailingWhitespace);
// Store the output obtained.
- if (!output_variable.empty() && !tempOutput.empty()) {
- this->Makefile->AddDefinition(output_variable, &*tempOutput.begin());
+ if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
+ this->Makefile->AddDefinition(arguments.OutputVariable, tempOutput.data());
}
- if (!merge_output && !error_variable.empty() && !tempError.empty()) {
- this->Makefile->AddDefinition(error_variable, &*tempError.begin());
+ if (!merge_output && !arguments.ErrorVariable.empty() &&
+ !tempError.empty()) {
+ this->Makefile->AddDefinition(arguments.ErrorVariable, tempError.data());
}
// Store the result of running the process.
- if (!result_variable.empty()) {
+ if (!arguments.ResultVariable.empty()) {
switch (cmsysProcess_GetState(cp)) {
case cmsysProcess_State_Exited: {
int v = cmsysProcess_GetExitValue(cp);
char buf[16];
sprintf(buf, "%d", v);
- this->Makefile->AddDefinition(result_variable, buf);
+ this->Makefile->AddDefinition(arguments.ResultVariable, buf);
} break;
case cmsysProcess_State_Exception:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
cmsysProcess_GetExceptionString(cp));
break;
case cmsysProcess_State_Error:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
cmsysProcess_GetErrorString(cp));
break;
case cmsysProcess_State_Expired:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
"Process terminated due to timeout");
break;
}
}
// Store the result of running the processes.
- if (!results_variable.empty()) {
+ if (!arguments.ResultsVariable.empty()) {
switch (cmsysProcess_GetState(cp)) {
case cmsysProcess_State_Exited: {
std::vector<std::string> res;
- for (size_t i = 0; i < cmds.size(); ++i) {
+ for (size_t i = 0; i < arguments.Commands.size(); ++i) {
switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
case kwsysProcess_StateByIndex_Exited: {
int exitCode =
@@ -339,27 +329,24 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
break;
}
}
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmJoin(res, ";").c_str());
} break;
case cmsysProcess_State_Exception:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmsysProcess_GetExceptionString(cp));
break;
case cmsysProcess_State_Error:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmsysProcess_GetErrorString(cp));
break;
case cmsysProcess_State_Expired:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
"Process terminated due to timeout");
break;
}
}
- // Delete the process instance.
- cmsysProcess_Delete(cp);
-
return true;
}
@@ -406,5 +393,5 @@ void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
--length;
}
#endif
- output.insert(output.end(), data, data + length);
+ cmAppend(output, data, data + length);
}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index ada270996..0a1e75582 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmExportFileGenerator.h"
#include "cmStateTypes.h"
@@ -39,7 +40,7 @@ public:
void GetTargets(std::vector<std::string>& targets) const;
void AppendTargets(std::vector<std::string> const& targets)
{
- this->Targets.insert(this->Targets.end(), targets.begin(), targets.end());
+ cmAppend(this->Targets, targets);
}
void SetExportSet(cmExportSet*);
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 722831a7f..a849aa246 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -2,10 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/RegularExpression.hxx"
+
+#include <algorithm>
#include <map>
#include <sstream>
+#include <utility>
+#include "cmArgumentParser.h"
#include "cmExportBuildAndroidMKGenerator.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExportSetMap.h"
@@ -13,10 +18,12 @@
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+class cmExportSet;
class cmExecutionStatus;
#if defined(__HAIKU__)
@@ -24,19 +31,6 @@ class cmExecutionStatus;
# include <StorageDefs.h>
#endif
-cmExportCommand::cmExportCommand()
- : Targets(&Helper, "TARGETS")
- , Append(&Helper, "APPEND", &ArgumentGroup)
- , ExportSetName(&Helper, "EXPORT", &ArgumentGroup)
- , Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
- , Filename(&Helper, "FILE", &ArgumentGroup)
- , ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup)
- , AndroidMKFile(&Helper, "ANDROID_MK")
-{
- this->ExportSet = nullptr;
-}
-
-// cmExportCommand
bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
@@ -48,45 +42,64 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
if (args[0] == "PACKAGE") {
return this->HandlePackage(args);
}
+
+ struct Arguments
+ {
+ std::string ExportSetName;
+ std::vector<std::string> Targets;
+ std::string Namespace;
+ std::string Filename;
+ std::string AndroidMKFile;
+ bool Append = false;
+ bool ExportOld = false;
+ };
+
+ auto parser = cmArgumentParser<Arguments>{}
+ .Bind("NAMESPACE"_s, &Arguments::Namespace)
+ .Bind("FILE"_s, &Arguments::Filename);
+
if (args[0] == "EXPORT") {
- this->ExportSetName.Follows(nullptr);
- this->ArgumentGroup.Follows(&this->ExportSetName);
+ parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
} else {
- this->Targets.Follows(nullptr);
- this->ArgumentGroup.Follows(&this->Targets);
+ parser.Bind("TARGETS"_s, &Arguments::Targets);
+ parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
+ parser.Bind("APPEND"_s, &Arguments::Append);
+ parser.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, &Arguments::ExportOld);
}
std::vector<std::string> unknownArgs;
- this->Helper.Parse(&args, &unknownArgs);
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unknownArgs, &keywordsMissingValue);
if (!unknownArgs.empty()) {
- this->SetError("Unknown arguments.");
+ this->SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
return false;
}
std::string fname;
bool android = false;
- if (this->AndroidMKFile.WasFound()) {
- fname = this->AndroidMKFile.GetString();
+ if (!arguments.AndroidMKFile.empty()) {
+ fname = arguments.AndroidMKFile;
android = true;
}
- if (!this->Filename.WasFound() && fname.empty()) {
+ if (arguments.Filename.empty() && fname.empty()) {
if (args[0] != "EXPORT") {
this->SetError("FILE <filename> option missing.");
return false;
}
- fname = this->ExportSetName.GetString() + ".cmake";
+ fname = arguments.ExportSetName + ".cmake";
} else if (fname.empty()) {
// Make sure the file has a .cmake extension.
- if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) !=
+ if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
".cmake") {
std::ostringstream e;
- e << "FILE option given filename \"" << this->Filename.GetString()
+ e << "FILE option given filename \"" << arguments.Filename
<< "\" which does not have an extension of \".cmake\".\n";
this->SetError(e.str());
return false;
}
- fname = this->Filename.GetString();
+ fname = arguments.Filename;
}
// Get the file to write.
@@ -108,33 +121,22 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ cmExportSet* ExportSet = nullptr;
if (args[0] == "EXPORT") {
- if (this->Append.IsEnabled()) {
- std::ostringstream e;
- e << "EXPORT signature does not recognise the APPEND option.";
- this->SetError(e.str());
- return false;
- }
-
- if (this->ExportOld.IsEnabled()) {
- std::ostringstream e;
- e << "EXPORT signature does not recognise the "
- "EXPORT_LINK_INTERFACE_LIBRARIES option.";
- this->SetError(e.str());
- return false;
- }
-
cmExportSetMap& setMap = gg->GetExportSets();
- std::string setName = this->ExportSetName.GetString();
- if (setMap.find(setName) == setMap.end()) {
+ auto const it = setMap.find(arguments.ExportSetName);
+ if (it == setMap.end()) {
std::ostringstream e;
- e << "Export set \"" << setName << "\" not found.";
+ e << "Export set \"" << arguments.ExportSetName << "\" not found.";
this->SetError(e.str());
return false;
}
- this->ExportSet = setMap[setName];
- } else if (this->Targets.WasFound()) {
- for (std::string const& currentTarget : this->Targets.GetVector()) {
+ ExportSet = it->second;
+ } else if (!arguments.Targets.empty() ||
+ std::find(keywordsMissingValue.begin(),
+ keywordsMissingValue.end(),
+ "TARGETS") != keywordsMissingValue.end()) {
+ for (std::string const& currentTarget : arguments.Targets) {
if (this->Makefile->IsAlias(currentTarget)) {
std::ostringstream e;
e << "given ALIAS target \"" << currentTarget
@@ -158,7 +160,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
}
targets.push_back(currentTarget);
}
- if (this->Append.IsEnabled()) {
+ if (arguments.Append) {
if (cmExportBuildFileGenerator* ebfg =
gg->GetExportedTargetsFile(fname)) {
ebfg->AppendTargets(targets);
@@ -178,15 +180,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
ebfg = new cmExportBuildFileGenerator;
}
ebfg->SetExportFile(fname.c_str());
- ebfg->SetNamespace(this->Namespace.GetCString());
- ebfg->SetAppendMode(this->Append.IsEnabled());
- if (this->ExportSet) {
- ebfg->SetExportSet(this->ExportSet);
+ ebfg->SetNamespace(arguments.Namespace);
+ ebfg->SetAppendMode(arguments.Append);
+ if (ExportSet != nullptr) {
+ ebfg->SetExportSet(ExportSet);
} else {
ebfg->SetTargets(targets);
}
this->Makefile->AddExportBuildFileGenerator(ebfg);
- ebfg->SetExportOld(this->ExportOld.IsEnabled());
+ ebfg->SetExportOld(arguments.ExportOld);
// Compute the set of configurations exported.
std::vector<std::string> configurationTypes;
@@ -197,7 +199,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
for (std::string const& ct : configurationTypes) {
ebfg->AddConfiguration(ct);
}
- if (this->ExportSet) {
+ if (ExportSet != nullptr) {
gg->AddBuildExportExportSet(ebfg);
} else {
gg->AddBuildExportSet(ebfg);
@@ -243,10 +245,23 @@ bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
return false;
}
- // If the CMAKE_EXPORT_NO_PACKAGE_REGISTRY variable is set the command
- // export(PACKAGE) does nothing.
- if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
- return true;
+ // CMP0090 decides both the default and what variable changes it.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0090)) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // Default is to export, but can be disabled.
+ if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Default is to not export, but can be enabled.
+ if (!this->Makefile->IsOn("CMAKE_EXPORT_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
}
// We store the current build directory in the registry as a value
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
index a5c6751bf..99f9932b9 100644
--- a/Source/cmExportCommand.h
+++ b/Source/cmExportCommand.h
@@ -9,21 +9,12 @@
#include <vector>
#include "cmCommand.h"
-#include "cmCommandArgumentsHelper.h"
class cmExecutionStatus;
-class cmExportSet;
-/** \class cmExportLibraryDependenciesCommand
- * \brief Add a test to the lists of tests to run.
- *
- * cmExportLibraryDependenciesCommand adds a test to the list of tests to run
- *
- */
class cmExportCommand : public cmCommand
{
public:
- cmExportCommand();
/**
* This is a virtual constructor for the command.
*/
@@ -37,21 +28,6 @@ public:
cmExecutionStatus& status) override;
private:
- cmCommandArgumentsHelper Helper;
- cmCommandArgumentGroup ArgumentGroup;
- cmCAStringVector Targets;
- cmCAEnabler Append;
- cmCAString ExportSetName;
- cmCAString Namespace;
- cmCAString Filename;
- cmCAEnabler ExportOld;
- cmCAString AndroidMKFile;
-
- cmExportSet* ExportSet;
-
- friend class cmExportBuildFileGenerator;
- std::string ErrorMessage;
-
bool HandlePackage(std::vector<std::string> const& args);
void StorePackageRegistryWin(std::string const& package, const char* content,
const char* hash);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index c8f743acd..a12e0c48d 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -70,8 +70,9 @@ bool cmExportFileGenerator::GenerateImportFile()
std::unique_ptr<cmsys::ofstream> foutPtr;
if (this->AppendMode) {
// Open for append.
+ auto openmodeApp = std::ios::app;
foutPtr = cm::make_unique<cmsys::ofstream>(this->MainImportFile.c_str(),
- std::ios::app);
+ openmodeApp);
} else {
// Generate atomically and with copy-if-different.
std::unique_ptr<cmGeneratedFileStream> ap(
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
index b4b2962b1..b60a0533c 100644
--- a/Source/cmExportLibraryDependenciesCommand.cxx
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -50,8 +50,9 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
// Use copy-if-different if not appending.
std::unique_ptr<cmsys::ofstream> foutPtr;
if (this->Append) {
+ const auto openmodeApp = std::ios::app;
foutPtr =
- cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), std::ios::app);
+ cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), openmodeApp);
} else {
std::unique_ptr<cmGeneratedFileStream> ap(
new cmGeneratedFileStream(this->Filename, true));
@@ -61,7 +62,7 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
std::ostream& fout = *foutPtr;
if (!fout) {
- cmSystemTools::Error("Error Writing ", this->Filename.c_str());
+ cmSystemTools::Error("Error Writing " + this->Filename);
cmSystemTools::ReportLastSystemError("");
return;
}
@@ -75,8 +76,7 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
std::map<std::string, std::string> libDepsNew;
std::map<std::string, std::string> libTypes;
for (cmMakefile* local : locals) {
- const cmTargets& tgts = local->GetTargets();
- for (auto const& tgt : tgts) {
+ for (auto const& tgt : local->GetTargets()) {
// Get the current target.
cmTarget const& target = tgt.second;
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
index 0ef306f63..d654c1285 100644
--- a/Source/cmExportSet.h
+++ b/Source/cmExportSet.h
@@ -25,6 +25,9 @@ public:
/// Destructor
~cmExportSet();
+ cmExportSet(const cmExportSet&) = delete;
+ cmExportSet& operator=(const cmExportSet&) = delete;
+
void Compute(cmLocalGenerator* lg);
void AddTargetExport(cmTargetExport* tgt);
diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx
index 074082835..293e80cf9 100644
--- a/Source/cmExportSetMap.cxx
+++ b/Source/cmExportSetMap.cxx
@@ -23,6 +23,8 @@ void cmExportSetMap::clear()
this->derived::clear();
}
+cmExportSetMap::cmExportSetMap() = default;
+
cmExportSetMap::~cmExportSetMap()
{
this->clear();
diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h
index 0f71c790c..385373240 100644
--- a/Source/cmExportSetMap.h
+++ b/Source/cmExportSetMap.h
@@ -25,8 +25,13 @@ public:
void clear();
+ cmExportSetMap();
+
/// Overloaded destructor deletes all member export sets.
~cmExportSetMap();
+
+ cmExportSetMap(const cmExportSetMap&) = delete;
+ cmExportSetMap& operator=(const cmExportSetMap&) = delete;
};
#endif
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index 4438f2803..a472a0691 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -31,13 +31,13 @@ public:
virtual void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile*, bool optional);
- ///! set the global generator which will generate the makefiles
+ //! set the global generator which will generate the makefiles
virtual void SetGlobalGenerator(cmGlobalGenerator* generator)
{
this->GlobalGenerator = generator;
}
- ///! Return the list of global generators supported by this extra generator
+ //! Return the list of global generators supported by this extra generator
const std::vector<std::string>& GetSupportedGlobalGenerators() const
{
return this->SupportedGlobalGenerators;
@@ -49,7 +49,7 @@ public:
static std::string CreateFullGeneratorName(
const std::string& globalGenerator, const std::string& extraGenerator);
- ///! Generate the project files, the Makefiles have already been generated
+ //! Generate the project files, the Makefiles have already been generated
virtual void Generate() = 0;
void SetName(const std::string& n) { Name = n; }
@@ -59,9 +59,9 @@ public:
bool dryRun);
protected:
- ///! Contains the names of the global generators support by this generator.
+ //! Contains the names of the global generators support by this generator.
std::vector<std::string> SupportedGlobalGenerators;
- ///! the global generator which creates the makefiles
+ //! the global generator which creates the makefiles
const cmGlobalGenerator* GlobalGenerator = nullptr;
std::string Name;
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index e408de384..f47744b60 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -13,6 +13,7 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
@@ -208,9 +209,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// Collect all files
std::vector<std::string> listFiles;
for (cmLocalGenerator* lg : it.second) {
- const std::vector<std::string>& files =
- lg->GetMakefile()->GetListFiles();
- listFiles.insert(listFiles.end(), files.begin(), files.end());
+ cmAppend(listFiles, lg->GetMakefile()->GetListFiles());
}
// Convert
@@ -247,8 +246,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// figure out the compiler
std::string compiler = this->GetCBCompilerId(mf);
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
cmXMLWriter xml(fout);
@@ -279,8 +278,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
xml.StartElement("Build");
- this->AppendTarget(xml, "all", nullptr, make.c_str(), lgs[0],
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, "all", nullptr, make, lgs[0], compiler, makeArgs);
// add all executable and library targets and some of the GLOBAL
// and UTILITY targets
@@ -293,8 +291,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// Only add the global targets from CMAKE_BINARY_DIR,
// not from the subdirs
if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
- this->AppendTarget(xml, targetName, nullptr, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
}
} break;
case cmStateEnums::UTILITY:
@@ -309,8 +307,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
break;
}
- this->AppendTarget(xml, targetName, nullptr, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
break;
case cmStateEnums::EXECUTABLE:
case cmStateEnums::STATIC_LIBRARY:
@@ -318,12 +316,12 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY: {
cmGeneratorTarget* gt = target;
- this->AppendTarget(xml, targetName, gt, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, gt, make, lg, compiler,
+ makeArgs);
std::string fastTarget = targetName;
fastTarget += "/fast";
- this->AppendTarget(xml, fastTarget, gt, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, fastTarget, gt, make, lg, compiler,
+ makeArgs);
} break;
default:
break;
@@ -377,7 +375,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
std::string const& fullPath = s->GetFullPath();
// Check file position relative to project root dir.
- const std::string& relative =
+ const std::string relative =
cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath);
// Do not add this file if it has ".." in relative path and
// if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
@@ -453,7 +451,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
}
// Add CMakeLists.txt
- tree.BuildUnit(xml, std::string(mf->GetHomeDirectory()) + "/");
+ tree.BuildUnit(xml, mf->GetHomeDirectory() + "/");
xml.EndElement(); // Project
xml.EndElement(); // CodeBlocks_project_file
@@ -488,8 +486,8 @@ std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
// Generate the xml code for one target.
void cmExtraCodeBlocksGenerator::AppendTarget(
cmXMLWriter& xml, const std::string& targetName, cmGeneratorTarget* target,
- const char* make, const cmLocalGenerator* lg, const char* compiler,
- const std::string& makeFlags)
+ const std::string& make, const cmLocalGenerator* lg,
+ const std::string& compiler, const std::string& makeFlags)
{
cmMakefile const* makefile = lg->GetMakefile();
std::string makefileName = lg->GetCurrentBinaryDirectory();
@@ -563,36 +561,32 @@ void cmExtraCodeBlocksGenerator::AppendTarget(
// the include directories for this target
std::vector<std::string> allIncludeDirs;
-
- std::vector<std::string> includes;
- lg->GetIncludeDirectories(includes, target, "C", buildType);
-
- allIncludeDirs.insert(allIncludeDirs.end(), includes.begin(),
- includes.end());
+ {
+ std::vector<std::string> includes;
+ lg->GetIncludeDirectories(includes, target, "C", buildType);
+ cmAppend(allIncludeDirs, includes);
+ }
std::string systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty()) {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
- allIncludeDirs.insert(allIncludeDirs.end(), dirs.begin(), dirs.end());
+ cmAppend(allIncludeDirs,
+ cmSystemTools::ExpandedListArgument(systemIncludeDirs));
}
systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty()) {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
- allIncludeDirs.insert(allIncludeDirs.end(), dirs.begin(), dirs.end());
+ cmAppend(allIncludeDirs,
+ cmSystemTools::ExpandedListArgument(systemIncludeDirs));
}
std::vector<std::string>::const_iterator end =
cmRemoveDuplicates(allIncludeDirs);
- for (std::vector<std::string>::const_iterator i = allIncludeDirs.begin();
- i != end; ++i) {
+ for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) {
xml.StartElement("Add");
- xml.Attribute("directory", *i);
+ xml.Attribute("directory", str);
xml.EndElement();
}
@@ -613,25 +607,23 @@ void cmExtraCodeBlocksGenerator::AppendTarget(
xml.StartElement("Build");
xml.Attribute(
"command",
- this->BuildMakeCommand(make, makefileName.c_str(), targetName, makeFlags));
+ this->BuildMakeCommand(make, makefileName, targetName, makeFlags));
xml.EndElement();
xml.StartElement("CompileFile");
- xml.Attribute("command",
- this->BuildMakeCommand(make, makefileName.c_str(), "\"$file\"",
- makeFlags));
+ xml.Attribute(
+ "command",
+ this->BuildMakeCommand(make, makefileName, "\"$file\"", makeFlags));
xml.EndElement();
xml.StartElement("Clean");
xml.Attribute(
- "command",
- this->BuildMakeCommand(make, makefileName.c_str(), "clean", makeFlags));
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
xml.EndElement();
xml.StartElement("DistClean");
xml.Attribute(
- "command",
- this->BuildMakeCommand(make, makefileName.c_str(), "clean", makeFlags));
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
xml.EndElement();
xml.EndElement(); // MakeCommands
@@ -725,8 +717,8 @@ int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
// Create the command line for building the given target using the selected
// make
std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
- const std::string& make, const char* makefile, const std::string& target,
- const std::string& makeFlags)
+ const std::string& make, const std::string& makefile,
+ const std::string& target, const std::string& makeFlags)
{
std::string command = make;
if (!makeFlags.empty()) {
@@ -747,7 +739,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
} else if (generator == "MinGW Makefiles") {
// no escaping of spaces in this case, see
// https://gitlab.kitware.com/cmake/cmake/issues/10014
- std::string makefileName = makefile;
+ std::string const& makefileName = makefile;
command += " -f \"";
command += makefileName;
command += "\" ";
diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h
index be3af2562..173e28400 100644
--- a/Source/cmExtraCodeBlocksGenerator.h
+++ b/Source/cmExtraCodeBlocksGenerator.h
@@ -42,12 +42,13 @@ private:
std::string GetCBCompilerId(const cmMakefile* mf);
int GetCBTargetType(cmGeneratorTarget* target);
- std::string BuildMakeCommand(const std::string& make, const char* makefile,
+ std::string BuildMakeCommand(const std::string& make,
+ const std::string& makefile,
const std::string& target,
const std::string& makeFlags);
void AppendTarget(cmXMLWriter& xml, const std::string& targetName,
- cmGeneratorTarget* target, const char* make,
- const cmLocalGenerator* lg, const char* compiler,
+ cmGeneratorTarget* target, const std::string& make,
+ const cmLocalGenerator* lg, const std::string& compiler,
const std::string& makeFlags);
};
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 0773edcbd..6fe8c147f 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -628,8 +628,8 @@ std::string cmExtraCodeLiteGenerator::GetConfigurationName(
std::string cmExtraCodeLiteGenerator::GetBuildCommand(
const cmMakefile* mf, const std::string& targetName) const
{
- std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string buildCommand = make; // Default
std::ostringstream ss;
if (generator == "NMake Makefiles" || generator == "Ninja") {
@@ -669,8 +669,8 @@ std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
const cmMakefile* mf) const
{
std::string buildCommand;
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
std::ostringstream ss;
#if defined(_WIN32)
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index e05f74ba5..aece3bc57 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -881,8 +881,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets");
xml.StartElement("buildTargets");
emmited.clear();
- const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
cmGlobalGenerator* generator =
@@ -1079,7 +1079,8 @@ void cmExtraEclipseCDT4Generator::AppendStorageScanners(
cmXMLWriter& xml, const cmMakefile& makefile)
{
// we need the "make" and the C (or C++) compiler which are used, Alex
- std::string make = makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& make =
+ makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
if (compiler.empty()) {
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index 23ba6b77f..877f10969 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -75,8 +75,8 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg,
cmGeneratedFileStream& fout) const
{
cmMakefile const* mf = lg->GetMakefile();
- const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
std::string const& homeOutputDir = lg->GetBinaryDirectory();
@@ -196,7 +196,7 @@ void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout,
{
static char JsonSep = ' ';
- fout << "\t\t\t" << JsonSep << "{\"name\":\"" << target
+ fout << "\t\t\t" << JsonSep << R"({"name":")" << target
<< "\", "
"\"build_cmd\":\""
<< make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 739a177bb..71c8fcd58 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -168,7 +168,7 @@ void cmExtraSublimeTextGenerator::AppendAllTargets(
const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
{
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string compiler;
if (!lgs.empty()) {
this->AppendTarget(fout, "all", lgs[0], nullptr, make.c_str(), mf,
@@ -263,7 +263,7 @@ void cmExtraSublimeTextGenerator::AppendTarget(
// Regular expression to extract compiler flags from a string
// https://gist.github.com/3944250
const char* regexString =
- "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
+ R"((^|[ ])-[DIOUWfgs][^= ]+(=\"[^"]+\"|=[^"][^ ]+)?)";
flagRegex.compile(regexString);
std::string workString =
flagsString + " " + definesString + " " + includesString;
@@ -315,12 +315,12 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
std::string generator = this->GlobalGenerator->GetName();
if (generator == "NMake Makefiles") {
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
- command += ", \"/NOLOGO\", \"/f\", \"";
+ command += R"(, "/NOLOGO", "/f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
} else if (generator == "Ninja") {
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
- command += ", \"-f\", \"";
+ command += R"(, "-f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
} else {
@@ -332,7 +332,7 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
} else {
makefileName = cmSystemTools::ConvertToOutputPath(makefile);
}
- command += ", \"-f\", \"";
+ command += R"(, "-f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
}
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 4b14d26d0..89629c768 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -6,6 +6,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -40,18 +41,17 @@ bool cmFLTKWrapUICommand::InitialPass(std::vector<std::string> const& args,
this->Makefile->AddIncludeDirectories(outputDirectories);
}
- for (std::vector<std::string>::const_iterator i = (args.begin() + 1);
- i != args.end(); i++) {
- cmSourceFile* curr = this->Makefile->GetSource(*i);
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should use the source GUI
// to generate .cxx and .h files
if (!curr || !curr->GetPropertyAsBool("WRAP_EXCLUDE")) {
std::string outName = outputDirectory;
outName += "/";
- outName += cmSystemTools::GetFilenameWithoutExtension(*i);
+ outName += cmSystemTools::GetFilenameWithoutExtension(arg);
std::string hname = outName;
hname += ".h";
- std::string origname = cdir + "/" + *i;
+ std::string origname = cdir + "/" + arg;
// add starting depends
std::vector<std::string> depends;
depends.push_back(origname);
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 34b6b330d..ba4266963 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -413,6 +413,14 @@ std::string cmFileAPI::ObjectName(Object const& o)
return name;
}
+Json::Value cmFileAPI::BuildVersion(unsigned int major, unsigned int minor)
+{
+ Json::Value version;
+ version["major"] = major;
+ version["minor"] = minor;
+ return version;
+}
+
Json::Value cmFileAPI::BuildObject(Object const& object)
{
Json::Value value;
@@ -680,10 +688,9 @@ Json::Value cmFileAPI::BuildCodeModel(Object const& object)
Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
codemodel["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = codemodel["version"] = Json::objectValue;
+ Json::Value& version = codemodel["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = CodeModelV2Minor;
+ version = BuildVersion(2, CodeModelV2Minor);
} else {
return codemodel; // should be unreachable
}
@@ -716,10 +723,9 @@ Json::Value cmFileAPI::BuildCache(Object const& object)
Json::Value cache = cmFileAPICacheDump(*this, object.Version);
cache["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = cache["version"] = Json::objectValue;
+ Json::Value& version = cache["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = CacheV2Minor;
+ version = BuildVersion(2, CacheV2Minor);
} else {
return cache; // should be unreachable
}
@@ -752,10 +758,9 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version);
cmakeFiles["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = cmakeFiles["version"] = Json::objectValue;
+ Json::Value& version = cmakeFiles["version"];
if (object.Version == 1) {
- version["major"] = 1;
- version["minor"] = CMakeFilesV1Minor;
+ version = BuildVersion(1, CMakeFilesV1Minor);
} else {
return cmakeFiles; // should be unreachable
}
@@ -788,13 +793,43 @@ Json::Value cmFileAPI::BuildInternalTest(Object const& object)
{
Json::Value test = Json::objectValue;
test["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = test["version"] = Json::objectValue;
+ Json::Value& version = test["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = InternalTestV2Minor;
+ version = BuildVersion(2, InternalTestV2Minor);
} else {
- version["major"] = 1;
- version["minor"] = InternalTestV1Minor;
+ version = BuildVersion(1, InternalTestV1Minor);
}
return test;
}
+
+Json::Value cmFileAPI::ReportCapabilities()
+{
+ Json::Value capabilities = Json::objectValue;
+ Json::Value& requests = capabilities["requests"] = Json::arrayValue;
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CodeModel);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CodeModelV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::Cache);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CacheV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CMakeFiles);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, CMakeFilesV1Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ return capabilities;
+}
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 341b072f4..602efa8ed 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -36,6 +36,9 @@ public:
and holding the original object. Other JSON types are unchanged. */
Json::Value MaybeJsonFile(Json::Value in, std::string const& prefix);
+ /** Report file-api capabilities for cmake -E capabilities. */
+ static Json::Value ReportCapabilities();
+
private:
cmake* CMakeInstance;
@@ -162,6 +165,8 @@ private:
static const char* ObjectKindName(ObjectKind kind);
static std::string ObjectName(Object const& o);
+ static Json::Value BuildVersion(unsigned int major, unsigned int minor);
+
Json::Value BuildObject(Object const& object);
ClientRequests BuildClientRequests(Json::Value const& requests);
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 45e830318..0fb166af5 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmFileAPICodemodel.h"
+#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmFileAPI.h"
#include "cmGeneratorExpression.h"
@@ -477,8 +478,7 @@ Json::Value CodemodelConfig::DumpTargets()
cmGlobalGenerator* gg =
this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
- std::vector<cmGeneratorTarget*> const& list = lg->GetGeneratorTargets();
- targetList.insert(targetList.end(), list.begin(), list.end());
+ cmAppend(targetList, lg->GetGeneratorTargets());
}
std::sort(targetList.begin(), targetList.end(),
[](cmGeneratorTarget* l, cmGeneratorTarget* r) {
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 0f911c170..7a3954e4d 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3,7 +3,7 @@
#include "cmFileCommand.h"
#include "cm_kwiml.h"
-#include "cmsys/Directory.hxx"
+#include "cm_static_string_view.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -16,24 +16,24 @@
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
#include "cmCryptoHash.h"
-#include "cmFSPermissions.h"
+#include "cmFileCopier.h"
+#include "cmFileInstaller.h"
#include "cmFileLockPool.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimes.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmHexFileConverter.h"
-#include "cmInstallType.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cm_sys_stat.h"
@@ -53,10 +53,6 @@
# include <windows.h>
#endif
-class cmSystemToolsFileTime;
-
-using namespace cmFSPermissions;
-
#if defined(_WIN32)
// libcurl doesn't support file:// urls for unicode filenames on Windows.
// Convert string from UTF-8 to ACP if this is a file:// URL.
@@ -223,7 +219,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
bool writable = false;
// Set permissions to writable
- if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+ if (cmSystemTools::GetPermissions(fileName, mode)) {
#if defined(_MSC_VER) || defined(__MINGW32__)
writable = (mode & S_IWRITE) != 0;
mode_t newMode = mode | S_IWRITE;
@@ -232,7 +228,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
mode_t newMode = mode | S_IWUSR | S_IWGRP;
#endif
if (!writable) {
- cmSystemTools::SetPermissions(fileName.c_str(), newMode);
+ cmSystemTools::SetPermissions(fileName, newMode);
}
}
// If GetPermissions fails, pretend like it is ok. File open will fail if
@@ -259,7 +255,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
}
file.close();
if (mode && !writable) {
- cmSystemTools::SetPermissions(fileName.c_str(), mode);
+ cmSystemTools::SetPermissions(fileName, mode);
}
return true;
}
@@ -272,36 +268,34 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
+ std::string const& fileNameArg = args[1];
+ std::string const& variable = args[2];
- cmCAString readArg(&argHelper, "READ");
- cmCAString fileNameArg(&argHelper, nullptr);
- cmCAString resultArg(&argHelper, nullptr);
+ struct Arguments
+ {
+ std::string Offset;
+ std::string Limit;
+ bool Hex = false;
+ };
- cmCAString offsetArg(&argHelper, "OFFSET", &group);
- cmCAString limitArg(&argHelper, "LIMIT", &group);
- cmCAEnabler hexOutputArg(&argHelper, "HEX", &group);
- readArg.Follows(nullptr);
- fileNameArg.Follows(&readArg);
- resultArg.Follows(&fileNameArg);
- group.Follows(&resultArg);
- argHelper.Parse(&args, nullptr);
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("OFFSET"_s, &Arguments::Offset)
+ .Bind("LIMIT"_s, &Arguments::Limit)
+ .Bind("HEX"_s, &Arguments::Hex);
- std::string fileName = fileNameArg.GetString();
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+
+ std::string fileName = fileNameArg;
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
fileName = this->Makefile->GetCurrentSourceDirectory();
- fileName += "/" + fileNameArg.GetString();
+ fileName += "/" + fileNameArg;
}
- std::string variable = resultArg.GetString();
-
// Open the specified file.
#if defined(_WIN32) || defined(__CYGWIN__)
- cmsys::ifstream file(
- fileName.c_str(),
- std::ios::in |
- (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
+ cmsys::ifstream file(fileName.c_str(),
+ arguments.Hex ? (std::ios::binary | std::ios::in)
+ : std::ios::in);
#else
cmsys::ifstream file(fileName.c_str());
#endif
@@ -317,21 +311,21 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
// is there a limit?
long sizeLimit = -1;
- if (!limitArg.GetString().empty()) {
- sizeLimit = atoi(limitArg.GetCString());
+ if (!arguments.Limit.empty()) {
+ sizeLimit = atoi(arguments.Limit.c_str());
}
// is there an offset?
long offset = 0;
- if (!offsetArg.GetString().empty()) {
- offset = atoi(offsetArg.GetCString());
+ if (!arguments.Offset.empty()) {
+ offset = atoi(arguments.Offset.c_str());
}
file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
std::string output;
- if (hexOutputArg.IsEnabled()) {
+ if (arguments.Hex) {
// Convert part of the file into hex code
char c;
while ((sizeLimit != 0) && (file.get(c))) {
@@ -393,7 +387,7 @@ bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
#else
std::ostringstream e;
e << args[0] << " not available during bootstrap";
- this->SetError(e.str().c_str());
+ this->SetError(e.str());
return false;
#endif
}
@@ -523,7 +517,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
maxlen = len;
arg_mode = arg_none;
} else if (arg_mode == arg_regex) {
- if (!regex.compile(args[i].c_str())) {
+ if (!regex.compile(args[i])) {
std::ostringstream e;
e << "STRINGS option REGEX value \"" << args[i]
<< "\" could not be compiled.";
@@ -563,8 +557,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
std::string binaryFileName = this->Makefile->GetCurrentBinaryDirectory();
binaryFileName += "/CMakeFiles";
binaryFileName += "/FileCommandStringsBinaryFile";
- if (cmHexFileConverter::TryConvert(fileName.c_str(),
- binaryFileName.c_str())) {
+ if (cmHexFileConverter::TryConvert(fileName, binaryFileName)) {
fileName = binaryFileName;
}
}
@@ -897,7 +890,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
}
std::vector<std::string>& foundFiles = g.GetFiles();
- files.insert(files.end(), foundFiles.begin(), foundFiles.end());
+ cmAppend(files, foundFiles);
if (configureDepends) {
std::sort(foundFiles.begin(), foundFiles.end());
@@ -947,16 +940,14 @@ bool cmFileCommand::HandleMakeDirectoryCommand(
// File command has at least one argument
assert(args.size() > 1);
- std::vector<std::string>::const_iterator i = args.begin();
-
- i++; // Get rid of subcommand
-
std::string expr;
- for (; i != args.end(); ++i) {
- const std::string* cdir = &(*i);
- if (!cmsys::SystemTools::FileIsFullPath(*i)) {
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ const std::string* cdir = &arg;
+ if (!cmsys::SystemTools::FileIsFullPath(arg)) {
expr = this->Makefile->GetCurrentSourceDirectory();
- expr += "/" + *i;
+ expr += "/" + arg;
cdir = &expr;
}
if (!this->Makefile->CanIWriteThisFile(*cdir)) {
@@ -981,15 +972,13 @@ bool cmFileCommand::HandleTouchCommand(std::vector<std::string> const& args,
// File command has at least one argument
assert(args.size() > 1);
- std::vector<std::string>::const_iterator i = args.begin();
-
- i++; // Get rid of subcommand
-
- for (; i != args.end(); ++i) {
- std::string tfile = *i;
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string tfile = arg;
if (!cmsys::SystemTools::FileIsFullPath(tfile)) {
tfile = this->Makefile->GetCurrentSourceDirectory();
- tfile += "/" + *i;
+ tfile += "/" + arg;
}
if (!this->Makefile->CanIWriteThisFile(tfile)) {
std::string e =
@@ -1061,1088 +1050,17 @@ bool cmFileCommand::HandleDifferentCommand(
return true;
}
-// File installation helper class.
-struct cmFileCopier
-{
- cmFileCopier(cmFileCommand* command, const char* name = "COPY")
- : FileCommand(command)
- , Makefile(command->GetMakefile())
- , Name(name)
- , Always(false)
- , MatchlessFiles(true)
- , FilePermissions(0)
- , DirPermissions(0)
- , CurrentMatchRule(nullptr)
- , UseGivenPermissionsFile(false)
- , UseGivenPermissionsDir(false)
- , UseSourcePermissions(true)
- , Doing(DoingNone)
- {
- }
- virtual ~cmFileCopier() = default;
-
- bool Run(std::vector<std::string> const& args);
-
-protected:
- cmFileCommand* FileCommand;
- cmMakefile* Makefile;
- const char* Name;
- bool Always;
- cmFileTimeComparison FileTimes;
-
- // Whether to install a file not matching any expression.
- bool MatchlessFiles;
-
- // Permissions for files and directories installed by this object.
- mode_t FilePermissions;
- mode_t DirPermissions;
-
- // Properties set by pattern and regex match rules.
- struct MatchProperties
- {
- bool Exclude = false;
- mode_t Permissions = 0;
- };
- struct MatchRule
- {
- cmsys::RegularExpression Regex;
- MatchProperties Properties;
- std::string RegexString;
- MatchRule(std::string const& regex)
- : Regex(regex.c_str())
- , RegexString(regex)
- {
- }
- };
- std::vector<MatchRule> MatchRules;
-
- // Get the properties from rules matching this input file.
- MatchProperties CollectMatchProperties(const char* file)
- {
-// Match rules are case-insensitive on some platforms.
-#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
- std::string lower = cmSystemTools::LowerCase(file);
- const char* file_to_match = lower.c_str();
-#else
- const char* file_to_match = file;
-#endif
-
- // Collect properties from all matching rules.
- bool matched = false;
- MatchProperties result;
- for (MatchRule& mr : this->MatchRules) {
- if (mr.Regex.find(file_to_match)) {
- matched = true;
- result.Exclude |= mr.Properties.Exclude;
- result.Permissions |= mr.Properties.Permissions;
- }
- }
- if (!matched && !this->MatchlessFiles) {
- result.Exclude = !cmSystemTools::FileIsDirectory(file);
- }
- return result;
- }
-
- bool SetPermissions(const char* toFile, mode_t permissions)
- {
- if (permissions) {
-#ifdef WIN32
- if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
- // Store the mode in an NTFS alternate stream.
- std::string mode_t_adt_filename =
- std::string(toFile) + ":cmake_mode_t";
-
- // Writing to an NTFS alternate stream changes the modification
- // time, so we need to save and restore its original value.
- cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
- cmSystemTools::FileTimeGet(toFile, file_time_orig);
-
- cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
-
- if (permissionStream) {
- permissionStream << std::oct << permissions << std::endl;
- }
-
- permissionStream.close();
-
- cmSystemTools::FileTimeSet(toFile, file_time_orig);
-
- cmSystemTools::FileTimeDelete(file_time_orig);
- }
-#endif
-
- if (!cmSystemTools::SetPermissions(toFile, permissions)) {
- std::ostringstream e;
- e << this->Name << " cannot set permissions on \"" << toFile << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- return true;
- }
-
- // Translate an argument to a permissions bit.
- bool CheckPermissions(std::string const& arg, mode_t& permissions)
- {
- if (!cmFSPermissions::stringToModeT(arg, permissions)) {
- std::ostringstream e;
- e << this->Name << " given invalid permission \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
- }
-
- bool InstallSymlink(const char* fromFile, const char* toFile);
- bool InstallFile(const char* fromFile, const char* toFile,
- MatchProperties match_properties);
- bool InstallDirectory(const char* source, const char* destination,
- MatchProperties match_properties);
- virtual bool Install(const char* fromFile, const char* toFile);
- virtual std::string const& ToName(std::string const& fromName)
- {
- return fromName;
- }
-
- enum Type
- {
- TypeFile,
- TypeDir,
- TypeLink
- };
- virtual void ReportCopy(const char*, Type, bool) {}
- virtual bool ReportMissing(const char* fromFile)
- {
- // The input file does not exist and installation is not optional.
- std::ostringstream e;
- e << this->Name << " cannot find \"" << fromFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- MatchRule* CurrentMatchRule;
- bool UseGivenPermissionsFile;
- bool UseGivenPermissionsDir;
- bool UseSourcePermissions;
- std::string Destination;
- std::string FilesFromDir;
- std::vector<std::string> Files;
- int Doing;
-
- virtual bool Parse(std::vector<std::string> const& args);
- enum
- {
- DoingNone,
- DoingError,
- DoingDestination,
- DoingFilesFromDir,
- DoingFiles,
- DoingPattern,
- DoingRegex,
- DoingPermissionsFile,
- DoingPermissionsDir,
- DoingPermissionsMatch,
- DoingLast1
- };
- virtual bool CheckKeyword(std::string const& arg);
- virtual bool CheckValue(std::string const& arg);
-
- void NotBeforeMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear before PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- void NotAfterMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear after PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- virtual void DefaultFilePermissions()
- {
- // Use read/write permissions.
- this->FilePermissions = 0;
- this->FilePermissions |= mode_owner_read;
- this->FilePermissions |= mode_owner_write;
- this->FilePermissions |= mode_group_read;
- this->FilePermissions |= mode_world_read;
- }
- virtual void DefaultDirectoryPermissions()
- {
- // Use read/write/executable permissions.
- this->DirPermissions = 0;
- this->DirPermissions |= mode_owner_read;
- this->DirPermissions |= mode_owner_write;
- this->DirPermissions |= mode_owner_execute;
- this->DirPermissions |= mode_group_read;
- this->DirPermissions |= mode_group_execute;
- this->DirPermissions |= mode_world_read;
- this->DirPermissions |= mode_world_execute;
- }
-
- bool GetDefaultDirectoryPermissions(mode_t** mode)
- {
- // check if default dir creation permissions were set
- const char* default_dir_install_permissions =
- this->Makefile->GetDefinition(
- "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
- if (default_dir_install_permissions && *default_dir_install_permissions) {
- std::vector<std::string> items;
- cmSystemTools::ExpandListArgument(default_dir_install_permissions,
- items);
- for (const auto& arg : items) {
- if (!this->CheckPermissions(arg, **mode)) {
- std::ostringstream e;
- e << this->FileCommand->GetError()
- << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
- "variable.";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- } else {
- *mode = nullptr;
- }
-
- return true;
- }
-};
-
-bool cmFileCopier::Parse(std::vector<std::string> const& args)
-{
- this->Doing = DoingFiles;
- for (unsigned int i = 1; i < args.size(); ++i) {
- // Check this argument.
- if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
- std::ostringstream e;
- e << "called with unknown argument \"" << args[i] << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Quit if an argument is invalid.
- if (this->Doing == DoingError) {
- return false;
- }
- }
-
- // Require a destination.
- if (this->Destination.empty()) {
- std::ostringstream e;
- e << this->Name << " given no DESTINATION";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // If file permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
- this->DefaultFilePermissions();
- }
-
- // If directory permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
- this->DefaultDirectoryPermissions();
- }
-
- return true;
-}
-
-bool cmFileCopier::CheckKeyword(std::string const& arg)
-{
- if (arg == "DESTINATION") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingDestination;
- }
- } else if (arg == "FILES_FROM_DIR") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFilesFromDir;
- }
- } else if (arg == "PATTERN") {
- this->Doing = DoingPattern;
- } else if (arg == "REGEX") {
- this->Doing = DoingRegex;
- } else if (arg == "EXCLUDE") {
- // Add this property to the current match rule.
- if (this->CurrentMatchRule) {
- this->CurrentMatchRule->Properties.Exclude = true;
- this->Doing = DoingNone;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "FILE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIRECTORY_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "USE_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = true;
- }
- } else if (arg == "NO_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = false;
- }
- } else if (arg == "FILES_MATCHING") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MatchlessFiles = false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingFiles:
- this->Files.push_back(arg);
- break;
- case DoingDestination:
- if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
- this->Destination = arg;
- } else {
- this->Destination = this->Makefile->GetCurrentBinaryDirectory();
- this->Destination += "/" + arg;
- }
- this->Doing = DoingNone;
- break;
- case DoingFilesFromDir:
- if (cmSystemTools::FileIsFullPath(arg)) {
- this->FilesFromDir = arg;
- } else {
- this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
- this->FilesFromDir += "/" + arg;
- }
- cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
- this->Doing = DoingNone;
- break;
- case DoingPattern: {
- // Convert the pattern to a regular expression. Require a
- // leading slash and trailing end-of-string in the matched
- // string to make sure the pattern matches only whole file
- // names.
- std::string regex = "/";
- regex += cmsys::Glob::PatternToRegex(arg, false);
- regex += "$";
- this->MatchRules.emplace_back(regex);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile PATTERN \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- } break;
- case DoingRegex:
- this->MatchRules.emplace_back(arg);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile REGEX \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsFile:
- if (!this->CheckPermissions(arg, this->FilePermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsDir:
- if (!this->CheckPermissions(arg, this->DirPermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsMatch:
- if (!this->CheckPermissions(
- arg, this->CurrentMatchRule->Properties.Permissions)) {
- this->Doing = DoingError;
- }
- break;
- default:
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::Run(std::vector<std::string> const& args)
-{
- if (!this->Parse(args)) {
- return false;
- }
-
- for (std::string const& f : this->Files) {
- std::string file;
- if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
- if (!this->FilesFromDir.empty()) {
- file = this->FilesFromDir;
- } else {
- file = this->Makefile->GetCurrentSourceDirectory();
- }
- file += "/";
- file += f;
- } else if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
- "to be specified as relative paths.");
- return false;
- } else {
- file = f;
- }
-
- // Split the input file into its directory and name components.
- std::vector<std::string> fromPathComponents;
- cmSystemTools::SplitPath(file, fromPathComponents);
- std::string fromName = *(fromPathComponents.end() - 1);
- std::string fromDir = cmSystemTools::JoinPath(
- fromPathComponents.begin(), fromPathComponents.end() - 1);
-
- // Compute the full path to the destination file.
- std::string toFile = this->Destination;
- if (!this->FilesFromDir.empty()) {
- std::string dir = cmSystemTools::GetFilenamePath(f);
- if (!dir.empty()) {
- toFile += "/";
- toFile += dir;
- }
- }
- std::string const& toName = this->ToName(fromName);
- if (!toName.empty()) {
- toFile += "/";
- toFile += toName;
- }
-
- // Construct the full path to the source file. The file name may
- // have been changed above.
- std::string fromFile = fromDir;
- if (!fromName.empty()) {
- fromFile += "/";
- fromFile += fromName;
- }
-
- if (!this->Install(fromFile.c_str(), toFile.c_str())) {
- return false;
- }
- }
- return true;
-}
-
-bool cmFileCopier::Install(const char* fromFile, const char* toFile)
-{
- if (!*fromFile) {
- std::ostringstream e;
- e << "INSTALL encountered an empty string input file name.";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Collect any properties matching this file name.
- MatchProperties match_properties = this->CollectMatchProperties(fromFile);
-
- // Skip the file if it is excluded.
- if (match_properties.Exclude) {
- return true;
- }
-
- if (cmSystemTools::SameFile(fromFile, toFile)) {
- return true;
- }
- if (cmSystemTools::FileIsSymlink(fromFile)) {
- return this->InstallSymlink(fromFile, toFile);
- }
- if (cmSystemTools::FileIsDirectory(fromFile)) {
- return this->InstallDirectory(fromFile, toFile, match_properties);
- }
- if (cmSystemTools::FileExists(fromFile)) {
- return this->InstallFile(fromFile, toFile, match_properties);
- }
- return this->ReportMissing(fromFile);
-}
-
-bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
-{
- // Read the original symlink.
- std::string symlinkTarget;
- if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
- std::ostringstream e;
- e << this->Name << " cannot read symlink \"" << fromFile
- << "\" to duplicate at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compare the symlink value to that at the destination if not
- // always installing.
- bool copy = true;
- if (!this->Always) {
- std::string oldSymlinkTarget;
- if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
- if (symlinkTarget == oldSymlinkTarget) {
- copy = false;
- }
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeLink, copy);
-
- if (copy) {
- // Remove the destination file so we can always create the symlink.
- cmSystemTools::RemoveFile(toFile);
-
- // Create destination directory if it doesn't exist
- cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
-
- // Create the symlink.
- if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot duplicate symlink \"" << fromFile
- << "\" at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- return true;
-}
-
-bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
- MatchProperties match_properties)
-{
- // Determine whether we will copy the file.
- bool copy = true;
- if (!this->Always) {
- // If both files exist with the same time do not copy.
- if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) {
- copy = false;
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeFile, copy);
-
- // Copy the file.
- if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
- std::ostringstream e;
- e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
- << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Set the file modification time of the destination file.
- if (copy && !this->Always) {
- // Add write permission so we can set the file time.
- // Permissions are set unconditionally below anyway.
- mode_t perm = 0;
- if (cmSystemTools::GetPermissions(toFile, perm)) {
- cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
- }
- if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot set modification time on \"" << toFile
- << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- // Set permissions of the destination file.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->FilePermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source file permissions be used.
- cmSystemTools::GetPermissions(fromFile, permissions);
- }
- return this->SetPermissions(toFile, permissions);
-}
-
-bool cmFileCopier::InstallDirectory(const char* source,
- const char* destination,
- MatchProperties match_properties)
-{
- // Inform the user about this directory installation.
- this->ReportCopy(destination, TypeDir,
- !cmSystemTools::FileIsDirectory(destination));
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- // Make sure the destination directory exists.
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::ostringstream e;
- e << this->Name << " cannot make directory \"" << destination
- << "\": " << cmSystemTools::GetLastSystemError();
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compute the requested permissions for the destination directory.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->DirPermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source directory permissions be used.
- cmSystemTools::GetPermissions(source, permissions);
- }
-
- // Compute the set of permissions required on this directory to
- // recursively install files and subdirectories safely.
- mode_t required_permissions =
- mode_owner_read | mode_owner_write | mode_owner_execute;
-
- // If the required permissions are specified it is safe to set the
- // final permissions now. Otherwise we must add the required
- // permissions temporarily during file installation.
- mode_t permissions_before = 0;
- mode_t permissions_after = 0;
- if ((permissions & required_permissions) == required_permissions) {
- permissions_before = permissions;
- } else {
- permissions_before = permissions | required_permissions;
- permissions_after = permissions;
- }
-
- // Set the required permissions of the destination directory.
- if (!this->SetPermissions(destination, permissions_before)) {
- return false;
- }
-
- // Load the directory contents to traverse it recursively.
- cmsys::Directory dir;
- if (source && *source) {
- dir.Load(source);
- }
- unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
- for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
- if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
- strcmp(dir.GetFile(fileNum), "..") == 0)) {
- std::string fromPath = source;
- fromPath += "/";
- fromPath += dir.GetFile(fileNum);
- std::string toPath = destination;
- toPath += "/";
- toPath += dir.GetFile(fileNum);
- if (!this->Install(fromPath.c_str(), toPath.c_str())) {
- return false;
- }
- }
- }
-
- // Set the requested permissions of the destination directory.
- return this->SetPermissions(destination, permissions_after);
-}
-
bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
{
cmFileCopier copier(this);
return copier.Run(args);
}
-struct cmFileInstaller : public cmFileCopier
-{
- cmFileInstaller(cmFileCommand* command)
- : cmFileCopier(command, "INSTALL")
- , InstallType(cmInstallType_FILES)
- , Optional(false)
- , MessageAlways(false)
- , MessageLazy(false)
- , MessageNever(false)
- , DestDirLength(0)
- {
- // Installation does not use source permissions by default.
- this->UseSourcePermissions = false;
- // Check whether to copy files always or only if they have changed.
- std::string install_always;
- if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
- this->Always = cmSystemTools::IsOn(install_always);
- }
- // Get the current manifest.
- this->Manifest =
- this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
- }
- ~cmFileInstaller() override
- {
- // Save the updated install manifest.
- this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
- this->Manifest.c_str());
- }
-
-protected:
- cmInstallType InstallType;
- bool Optional;
- bool MessageAlways;
- bool MessageLazy;
- bool MessageNever;
- int DestDirLength;
- std::string Rename;
-
- std::string Manifest;
- void ManifestAppend(std::string const& file)
- {
- if (!this->Manifest.empty()) {
- this->Manifest += ";";
- }
- this->Manifest += file.substr(this->DestDirLength);
- }
-
- std::string const& ToName(std::string const& fromName) override
- {
- return this->Rename.empty() ? fromName : this->Rename;
- }
-
- void ReportCopy(const char* toFile, Type type, bool copy) override
- {
- if (!this->MessageNever && (copy || !this->MessageLazy)) {
- std::string message = (copy ? "Installing: " : "Up-to-date: ");
- message += toFile;
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (type != TypeDir) {
- // Add the file to the manifest.
- this->ManifestAppend(toFile);
- }
- }
- bool ReportMissing(const char* fromFile) override
- {
- return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
- }
- bool Install(const char* fromFile, const char* toFile) override
- {
- // Support installing from empty source to make a directory.
- if (this->InstallType == cmInstallType_DIRECTORY && !*fromFile) {
- return this->InstallDirectory(fromFile, toFile, MatchProperties());
- }
- return this->cmFileCopier::Install(fromFile, toFile);
- }
-
- bool Parse(std::vector<std::string> const& args) override;
- enum
- {
- DoingType = DoingLast1,
- DoingRename,
- DoingLast2
- };
- bool CheckKeyword(std::string const& arg) override;
- bool CheckValue(std::string const& arg) override;
- void DefaultFilePermissions() override
- {
- this->cmFileCopier::DefaultFilePermissions();
- // Add execute permissions based on the target type.
- switch (this->InstallType) {
- case cmInstallType_SHARED_LIBRARY:
- case cmInstallType_MODULE_LIBRARY:
- if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
- break;
- }
- CM_FALLTHROUGH;
- case cmInstallType_EXECUTABLE:
- case cmInstallType_PROGRAMS:
- this->FilePermissions |= mode_owner_execute;
- this->FilePermissions |= mode_group_execute;
- this->FilePermissions |= mode_world_execute;
- break;
- default:
- break;
- }
- }
- bool GetTargetTypeFromString(const std::string& stype);
- bool HandleInstallDestination();
-};
-
-bool cmFileInstaller::Parse(std::vector<std::string> const& args)
-{
- if (!this->cmFileCopier::Parse(args)) {
- return false;
- }
-
- if (!this->Rename.empty()) {
- if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("INSTALL option RENAME may not be "
- "combined with FILES_FROM_DIR.");
- return false;
- }
- if (this->InstallType != cmInstallType_FILES &&
- this->InstallType != cmInstallType_PROGRAMS) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with FILES or PROGRAMS.");
- return false;
- }
- if (this->Files.size() > 1) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with one file.");
- return false;
- }
- }
-
- if (!this->HandleInstallDestination()) {
- return false;
- }
-
- if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
- (this->MessageNever ? 1 : 0)) > 1) {
- this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
- "MESSAGE_LAZY, and MESSAGE_NEVER "
- "are mutually exclusive.");
- return false;
- }
-
- return true;
-}
-
-bool cmFileInstaller::CheckKeyword(std::string const& arg)
-{
- if (arg == "TYPE") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingType;
- }
- } else if (arg == "FILES") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFiles;
- }
- } else if (arg == "RENAME") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingRename;
- }
- } else if (arg == "OPTIONAL") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->Optional = true;
- }
- } else if (arg == "MESSAGE_ALWAYS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageAlways = true;
- }
- } else if (arg == "MESSAGE_LAZY") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageLazy = true;
- }
- } else if (arg == "MESSAGE_NEVER") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageNever = true;
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIR_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
- arg == "PROPERTIES") {
- std::ostringstream e;
- e << "INSTALL called with old-style " << arg << " argument. "
- << "This script was generated with an older version of CMake. "
- << "Re-run this cmake version on your build tree.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- } else {
- return this->cmFileCopier::CheckKeyword(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingType:
- if (!this->GetTargetTypeFromString(arg)) {
- this->Doing = DoingError;
- }
- break;
- case DoingRename:
- this->Rename = arg;
- break;
- default:
- return this->cmFileCopier::CheckValue(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
-{
- if (stype == "EXECUTABLE") {
- this->InstallType = cmInstallType_EXECUTABLE;
- } else if (stype == "FILE") {
- this->InstallType = cmInstallType_FILES;
- } else if (stype == "PROGRAM") {
- this->InstallType = cmInstallType_PROGRAMS;
- } else if (stype == "STATIC_LIBRARY") {
- this->InstallType = cmInstallType_STATIC_LIBRARY;
- } else if (stype == "SHARED_LIBRARY") {
- this->InstallType = cmInstallType_SHARED_LIBRARY;
- } else if (stype == "MODULE") {
- this->InstallType = cmInstallType_MODULE_LIBRARY;
- } else if (stype == "DIRECTORY") {
- this->InstallType = cmInstallType_DIRECTORY;
- } else {
- std::ostringstream e;
- e << "Option TYPE given unknown value \"" << stype << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
-}
-
-bool cmFileInstaller::HandleInstallDestination()
-{
- std::string& destination = this->Destination;
-
- // allow for / to be a valid destination
- if (destination.size() < 2 && destination != "/") {
- this->FileCommand->SetError("called with inappropriate arguments. "
- "No DESTINATION provided or .");
- return false;
- }
-
- std::string sdestdir;
- if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
- cmSystemTools::ConvertToUnixSlashes(sdestdir);
- char ch1 = destination[0];
- char ch2 = destination[1];
- char ch3 = 0;
- if (destination.size() > 2) {
- ch3 = destination[2];
- }
- int skip = 0;
- if (ch1 != '/') {
- int relative = 0;
- if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
- ch2 == ':') {
- // Assume windows
- // let's do some destdir magic:
- skip = 2;
- if (ch3 != '/') {
- relative = 1;
- }
- } else {
- relative = 1;
- }
- if (relative) {
- // This is relative path on unix or windows. Since we are doing
- // destdir, this case does not make sense.
- this->FileCommand->SetError(
- "called with relative DESTINATION. This "
- "does not make sense when using DESTDIR. Specify "
- "absolute path or remove DESTDIR environment variable.");
- return false;
- }
- } else {
- if (ch2 == '/') {
- // looks like a network path.
- std::string message =
- "called with network path DESTINATION. This "
- "does not make sense when using DESTDIR. Specify local "
- "absolute path or remove DESTDIR environment variable."
- "\nDESTINATION=\n";
- message += destination;
- this->FileCommand->SetError(message);
- return false;
- }
- }
- destination = sdestdir + (destination.c_str() + skip);
- this->DestDirLength = int(sdestdir.size());
- }
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- if (this->InstallType != cmInstallType_DIRECTORY) {
- if (!cmSystemTools::FileExists(destination)) {
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::string errstring = "cannot create directory: " + destination +
- ". Maybe need administrative privileges.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- if (!cmSystemTools::FileIsDirectory(destination)) {
- std::string errstring =
- "INSTALL destination: " + destination + " is not a directory.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- return true;
-}
-
bool cmFileCommand::HandleRPathChangeCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
const char* oldRPath = nullptr;
const char* newRPath = nullptr;
enum Doing
@@ -2161,7 +1079,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
} else if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else if (doing == DoingOld) {
oldRPath = args[i].c_str();
@@ -2176,7 +1094,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_CHANGE not given FILE option.");
return false;
}
@@ -2195,8 +1113,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
return false;
}
bool success = true;
- cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
- bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ cmFileTimes const ft(file);
std::string emsg;
bool changed;
if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed)) {
@@ -2218,13 +1135,10 @@ bool cmFileCommand::HandleRPathChangeCommand(
message += "\" to \"";
message += newRPath;
message += "\"";
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (have_ft) {
- cmSystemTools::FileTimeSet(file, ft);
+ this->Makefile->DisplayStatus(message, -1);
}
+ ft.Store(file);
}
- cmSystemTools::FileTimeDelete(ft);
return success;
}
@@ -2232,7 +1146,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
enum Doing
{
DoingNone,
@@ -2243,7 +1157,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else {
std::ostringstream e;
@@ -2252,7 +1166,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_REMOVE not given FILE option.");
return false;
}
@@ -2263,8 +1177,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
return false;
}
bool success = true;
- cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
- bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ cmFileTimes const ft(file);
std::string emsg;
bool removed;
if (!cmSystemTools::RemoveRPath(file, &emsg, &removed)) {
@@ -2282,13 +1195,10 @@ bool cmFileCommand::HandleRPathRemoveCommand(
std::string message = "Removed runtime path from \"";
message += file;
message += "\"";
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (have_ft) {
- cmSystemTools::FileTimeSet(file, ft);
+ this->Makefile->DisplayStatus(message, -1);
}
+ ft.Store(file);
}
- cmSystemTools::FileTimeDelete(ft);
return success;
}
@@ -2296,7 +1206,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
const char* rpath = nullptr;
enum Doing
{
@@ -2311,7 +1221,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
} else if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else if (doing == DoingRPath) {
rpath = args[i].c_str();
@@ -2323,7 +1233,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_CHECK not given FILE option.");
return false;
}
@@ -2351,55 +1261,54 @@ bool cmFileCommand::HandleReadElfCommand(std::vector<std::string> const& args)
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
-
- cmCAString readArg(&argHelper, "READ_ELF");
- cmCAString fileNameArg(&argHelper, nullptr);
+ std::string const& fileNameArg = args[1];
- cmCAString rpathArg(&argHelper, "RPATH", &group);
- cmCAString runpathArg(&argHelper, "RUNPATH", &group);
- cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group);
+ struct Arguments
+ {
+ std::string RPath;
+ std::string RunPath;
+ std::string Error;
+ };
- readArg.Follows(nullptr);
- fileNameArg.Follows(&readArg);
- group.Follows(&fileNameArg);
- argHelper.Parse(&args, nullptr);
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("RPATH"_s, &Arguments::RPath)
+ .Bind("RUNPATH"_s, &Arguments::RunPath)
+ .Bind("CAPTURE_ERROR"_s, &Arguments::Error);
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2));
- if (!cmSystemTools::FileExists(fileNameArg.GetString(), true)) {
+ if (!cmSystemTools::FileExists(fileNameArg, true)) {
std::ostringstream e;
- e << "READ_ELF given FILE \"" << fileNameArg.GetString()
- << "\" that does not exist.";
+ e << "READ_ELF given FILE \"" << fileNameArg << "\" that does not exist.";
this->SetError(e.str());
return false;
}
#if defined(CMAKE_USE_ELF_PARSER)
- cmELF elf(fileNameArg.GetCString());
+ cmELF elf(fileNameArg.c_str());
- if (!rpathArg.GetString().empty()) {
+ if (!arguments.RPath.empty()) {
if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
std::string rpath(se_rpath->Value);
std::replace(rpath.begin(), rpath.end(), ':', ';');
- this->Makefile->AddDefinition(rpathArg.GetString(), rpath.c_str());
+ this->Makefile->AddDefinition(arguments.RPath, rpath.c_str());
}
}
- if (!runpathArg.GetString().empty()) {
+ if (!arguments.RunPath.empty()) {
if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
std::string runpath(se_runpath->Value);
std::replace(runpath.begin(), runpath.end(), ':', ';');
- this->Makefile->AddDefinition(runpathArg.GetString(), runpath.c_str());
+ this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str());
}
}
return true;
#else
std::string error = "ELF parser not available on this platform.";
- if (errorArg.GetString().empty()) {
+ if (arguments.Error.empty()) {
this->SetError(error);
return false;
}
- this->Makefile->AddDefinition(errorArg.GetString(), error.c_str());
+ this->Makefile->AddDefinition(arguments.Error, error.c_str());
return true;
#endif
}
@@ -2481,14 +1390,20 @@ bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
{
std::string message;
- std::vector<std::string>::const_iterator i = args.begin();
- i++; // Get rid of subcommand
- for (; i != args.end(); ++i) {
- std::string fileName = *i;
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string fileName = arg;
+ if (fileName.empty()) {
+ std::string const r = recurse ? "REMOVE_RECURSE" : "REMOVE";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING,
+ "Ignoring empty file name in " + r + ".");
+ continue;
+ }
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
fileName = this->Makefile->GetCurrentSourceDirectory();
- fileName += "/" + *i;
+ fileName += "/" + arg;
}
if (cmSystemTools::FileIsDirectory(fileName) &&
@@ -2501,44 +1416,43 @@ bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
return true;
}
+namespace {
+std::string ToNativePath(const std::string& path)
+{
+ const auto& outPath = cmSystemTools::ConvertToOutputPath(path);
+ if (outPath.size() > 1 && outPath.front() == '\"' &&
+ outPath.back() == '\"') {
+ return outPath.substr(1, outPath.size() - 2);
+ }
+ return outPath;
+}
+
+std::string ToCMakePath(const std::string& path)
+{
+ auto temp = path;
+ cmSystemTools::ConvertToUnixSlashes(temp);
+ return temp;
+}
+}
+
bool cmFileCommand::HandleCMakePathCommand(
std::vector<std::string> const& args, bool nativePath)
{
- std::vector<std::string>::const_iterator i = args.begin();
if (args.size() != 3) {
this->SetError("FILE([TO_CMAKE_PATH|TO_NATIVE_PATH] path result) must be "
"called with exactly three arguments.");
return false;
}
- i++; // Get rid of subcommand
#if defined(_WIN32) && !defined(__CYGWIN__)
char pathSep = ';';
#else
char pathSep = ':';
#endif
- std::vector<std::string> path = cmSystemTools::SplitString(*i, pathSep);
- i++;
- const char* var = i->c_str();
- std::string value;
- for (std::vector<std::string>::iterator j = path.begin(); j != path.end();
- ++j) {
- if (j != path.begin()) {
- value += ";";
- }
- if (!nativePath) {
- cmSystemTools::ConvertToUnixSlashes(*j);
- } else {
- *j = cmSystemTools::ConvertToOutputPath(*j);
- // remove double quotes in the path
- std::string& s = *j;
+ std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
- if (s.size() > 1 && s.front() == '\"' && s.back() == '\"') {
- s = s.substr(1, s.size() - 2);
- }
- }
- value += *j;
- }
- this->Makefile->AddDefinition(var, value.c_str());
+ std::string value = cmJoin(
+ cmMakeRange(path).transform(nativePath ? ToNativePath : ToCMakePath), ";");
+ this->Makefile->AddDefinition(args[2], value.c_str());
return true;
}
@@ -2562,23 +1476,22 @@ size_t cmWriteToMemoryCallback(void* ptr, size_t size, size_t nmemb,
void* data)
{
int realsize = static_cast<int>(size * nmemb);
- cmFileCommandVectorOfChar* vec =
- static_cast<cmFileCommandVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
+ cmAppend(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
return realsize;
}
size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
size_t size, void* data)
{
- cmFileCommandVectorOfChar* vec =
- static_cast<cmFileCommandVectorOfChar*>(data);
+ cmFileCommandVectorOfChar& vec =
+ *static_cast<cmFileCommandVectorOfChar*>(data);
switch (type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_IN:
case CURLINFO_HEADER_OUT:
- vec->insert(vec->end(), chPtr, chPtr + size);
+ cmAppend(vec, chPtr, chPtr + size);
break;
case CURLINFO_DATA_IN:
case CURLINFO_DATA_OUT:
@@ -2588,7 +1501,7 @@ size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n",
static_cast<KWIML_INT_uint64_t>(size));
if (n > 0) {
- vec->insert(vec->end(), buf, buf + n);
+ cmAppend(vec, buf, buf + n);
}
} break;
default:
@@ -2651,7 +1564,7 @@ int cmFileDownloadProgressCallback(void* clientp, double dltotal, double dlnow,
if (helper->UpdatePercentage(dlnow, dltotal, status)) {
cmFileCommand* fc = helper->GetFileCommand();
cmMakefile* mf = fc->GetMakefile();
- mf->DisplayStatus(status.c_str(), -1);
+ mf->DisplayStatus(status, -1);
}
return 0;
@@ -2669,7 +1582,7 @@ int cmFileUploadProgressCallback(void* clientp, double dltotal, double dlnow,
if (helper->UpdatePercentage(ulnow, ultotal, status)) {
cmFileCommand* fc = helper->GetFileCommand();
cmMakefile* mf = fc->GetMakefile();
- mf->DisplayStatus(status.c_str(), -1);
+ mf->DisplayStatus(status, -1);
}
return 0;
@@ -2693,6 +1606,9 @@ public:
}
}
+ cURLEasyGuard(const cURLEasyGuard&) = delete;
+ cURLEasyGuard& operator=(const cURLEasyGuard&) = delete;
+
void release() { this->Easy = nullptr; }
private:
@@ -3067,7 +1983,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
if (!logVar.empty()) {
chunkDebug.push_back(0);
- this->Makefile->AddDefinition(logVar, &*chunkDebug.begin());
+ this->Makefile->AddDefinition(logVar, chunkDebug.data());
}
return true;
@@ -3326,14 +2242,14 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
if (!chunkResponse.empty()) {
chunkResponse.push_back(0);
log += "Response:\n";
- log += &*chunkResponse.begin();
+ log += chunkResponse.data();
log += "\n";
}
if (!chunkDebug.empty()) {
chunkDebug.push_back(0);
log += "Debug:\n";
- log += &*chunkDebug.begin();
+ log += chunkDebug.data();
log += "\n";
}
@@ -3674,44 +2590,39 @@ bool cmFileCommand::HandleCreateLinkCommand(
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
-
- cmCAString linkArg(&argHelper, "CREATE_LINK");
- cmCAString fileArg(&argHelper, nullptr);
- cmCAString newFileArg(&argHelper, nullptr);
+ std::string const& fileName = args[1];
+ std::string const& newFileName = args[2];
- cmCAString resultArg(&argHelper, "RESULT", &group);
- cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group);
- cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group);
+ struct Arguments
+ {
+ std::string Result;
+ bool CopyOnError = false;
+ bool Symbolic = false;
+ };
- linkArg.Follows(nullptr);
- fileArg.Follows(&linkArg);
- newFileArg.Follows(&fileArg);
- group.Follows(&newFileArg);
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESULT"_s, &Arguments::Result)
+ .Bind("COPY_ON_ERROR"_s, &Arguments::CopyOnError)
+ .Bind("SYMBOLIC"_s, &Arguments::Symbolic);
std::vector<std::string> unconsumedArgs;
- argHelper.Parse(&args, &unconsumedArgs);
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
if (!unconsumedArgs.empty()) {
this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
return false;
}
- std::string fileName = fileArg.GetString();
- std::string newFileName = newFileArg.GetString();
-
- // Output variable for storing the result.
- const std::string& resultVar = resultArg.GetString();
-
// The system error message generated in the operation.
std::string result;
// Check if the paths are distinct.
if (fileName == newFileName) {
result = "CREATE_LINK cannot use same file and newfile";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
return true;
}
this->SetError(result);
@@ -3719,10 +2630,10 @@ bool cmFileCommand::HandleCreateLinkCommand(
}
// Hard link requires original file to exist.
- if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) {
+ if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
return true;
}
this->SetError(result);
@@ -3738,8 +2649,8 @@ bool cmFileCommand::HandleCreateLinkCommand(
<< "' because existing path cannot be removed: "
<< cmSystemTools::GetLastSystemError() << "\n";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, e.str().c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, e.str().c_str());
return true;
}
this->SetError(e.str());
@@ -3750,15 +2661,15 @@ bool cmFileCommand::HandleCreateLinkCommand(
bool completed = false;
// Check if the command requires a symbolic link.
- if (symbolicArg.IsEnabled()) {
+ if (arguments.Symbolic) {
completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result);
} else {
completed = cmSystemTools::CreateLink(fileName, newFileName, &result);
}
// Check if copy-on-error is enabled in the arguments.
- if (!completed && copyOnErrorArg.IsEnabled()) {
- completed = cmSystemTools::cmCopyFile(fileName, newFileName);
+ if (!completed && arguments.CopyOnError) {
+ completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
if (!completed) {
result = "Copy failed: " + cmSystemTools::GetLastSystemError();
}
@@ -3767,14 +2678,14 @@ bool cmFileCommand::HandleCreateLinkCommand(
// Check if the operation was successful.
if (completed) {
result = "0";
- } else if (resultVar.empty()) {
+ } else if (arguments.Result.empty()) {
// The operation failed and the result is not reported in a variable.
this->SetError(result);
return false;
}
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
}
return true;
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
new file mode 100644
index 000000000..49e8cd5b3
--- /dev/null
+++ b/Source/cmFileCopier.cxx
@@ -0,0 +1,713 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileCopier.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmFileTimes.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmsys/Directory.hxx"
+#include "cmsys/Glob.hxx"
+
+#ifdef _WIN32
+# include "cmsys/FStream.hxx"
+#endif
+
+#include <sstream>
+#include <string.h>
+
+using namespace cmFSPermissions;
+
+cmFileCopier::cmFileCopier(cmFileCommand* command, const char* name)
+ : FileCommand(command)
+ , Makefile(command->GetMakefile())
+ , Name(name)
+ , Always(false)
+ , MatchlessFiles(true)
+ , FilePermissions(0)
+ , DirPermissions(0)
+ , CurrentMatchRule(nullptr)
+ , UseGivenPermissionsFile(false)
+ , UseGivenPermissionsDir(false)
+ , UseSourcePermissions(true)
+ , FollowSymlinkChain(false)
+ , Doing(DoingNone)
+{
+}
+
+cmFileCopier::~cmFileCopier() = default;
+
+cmFileCopier::MatchProperties cmFileCopier::CollectMatchProperties(
+ const std::string& file)
+{
+ // Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+ const std::string file_to_match = cmSystemTools::LowerCase(file);
+#else
+ const std::string& file_to_match = file;
+#endif
+
+ // Collect properties from all matching rules.
+ bool matched = false;
+ MatchProperties result;
+ for (MatchRule& mr : this->MatchRules) {
+ if (mr.Regex.find(file_to_match)) {
+ matched = true;
+ result.Exclude |= mr.Properties.Exclude;
+ result.Permissions |= mr.Properties.Permissions;
+ }
+ }
+ if (!matched && !this->MatchlessFiles) {
+ result.Exclude = !cmSystemTools::FileIsDirectory(file);
+ }
+ return result;
+}
+
+bool cmFileCopier::SetPermissions(const std::string& toFile,
+ mode_t permissions)
+{
+ if (permissions) {
+#ifdef WIN32
+ if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ // Store the mode in an NTFS alternate stream.
+ std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
+
+ // Writing to an NTFS alternate stream changes the modification
+ // time, so we need to save and restore its original value.
+ cmFileTimes file_time_orig(toFile);
+ {
+ cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
+ if (permissionStream) {
+ permissionStream << std::oct << permissions << std::endl;
+ }
+ permissionStream.close();
+ }
+ file_time_orig.Store(toFile);
+ }
+#endif
+
+ if (!cmSystemTools::SetPermissions(toFile, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set permissions on \"" << toFile << "\"";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+// Translate an argument to a permissions bit.
+bool cmFileCopier::CheckPermissions(std::string const& arg,
+ mode_t& permissions)
+{
+ if (!cmFSPermissions::stringToModeT(arg, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " given invalid permission \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+std::string const& cmFileCopier::ToName(std::string const& fromName)
+{
+ return fromName;
+}
+
+bool cmFileCopier::ReportMissing(const std::string& fromFile)
+{
+ // The input file does not exist and installation is not optional.
+ std::ostringstream e;
+ e << this->Name << " cannot find \"" << fromFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+}
+
+void cmFileCopier::NotBeforeMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear before PATTERN or REGEX.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::NotAfterMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear after PATTERN or REGEX.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::DefaultFilePermissions()
+{
+ // Use read/write permissions.
+ this->FilePermissions = 0;
+ this->FilePermissions |= mode_owner_read;
+ this->FilePermissions |= mode_owner_write;
+ this->FilePermissions |= mode_group_read;
+ this->FilePermissions |= mode_world_read;
+}
+
+void cmFileCopier::DefaultDirectoryPermissions()
+{
+ // Use read/write/executable permissions.
+ this->DirPermissions = 0;
+ this->DirPermissions |= mode_owner_read;
+ this->DirPermissions |= mode_owner_write;
+ this->DirPermissions |= mode_owner_execute;
+ this->DirPermissions |= mode_group_read;
+ this->DirPermissions |= mode_group_execute;
+ this->DirPermissions |= mode_world_read;
+ this->DirPermissions |= mode_world_execute;
+}
+
+bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
+{
+ // check if default dir creation permissions were set
+ const char* default_dir_install_permissions = this->Makefile->GetDefinition(
+ "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (default_dir_install_permissions && *default_dir_install_permissions) {
+ std::vector<std::string> items;
+ cmSystemTools::ExpandListArgument(default_dir_install_permissions, items);
+ for (const auto& arg : items) {
+ if (!this->CheckPermissions(arg, **mode)) {
+ std::ostringstream e;
+ e << this->FileCommand->GetError()
+ << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
+ "variable.";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+ } else {
+ *mode = nullptr;
+ }
+
+ return true;
+}
+
+bool cmFileCopier::Parse(std::vector<std::string> const& args)
+{
+ this->Doing = DoingFiles;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ // Check this argument.
+ if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
+ std::ostringstream e;
+ e << "called with unknown argument \"" << args[i] << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Quit if an argument is invalid.
+ if (this->Doing == DoingError) {
+ return false;
+ }
+ }
+
+ // Require a destination.
+ if (this->Destination.empty()) {
+ std::ostringstream e;
+ e << this->Name << " given no DESTINATION";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // If file permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
+ this->DefaultFilePermissions();
+ }
+
+ // If directory permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
+ this->DefaultDirectoryPermissions();
+ }
+
+ return true;
+}
+
+bool cmFileCopier::CheckKeyword(std::string const& arg)
+{
+ if (arg == "DESTINATION") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingDestination;
+ }
+ } else if (arg == "FILES_FROM_DIR") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFilesFromDir;
+ }
+ } else if (arg == "PATTERN") {
+ this->Doing = DoingPattern;
+ } else if (arg == "REGEX") {
+ this->Doing = DoingRegex;
+ } else if (arg == "FOLLOW_SYMLINK_CHAIN") {
+ this->FollowSymlinkChain = true;
+ this->Doing = DoingNone;
+ } else if (arg == "EXCLUDE") {
+ // Add this property to the current match rule.
+ if (this->CurrentMatchRule) {
+ this->CurrentMatchRule->Properties.Exclude = true;
+ this->Doing = DoingNone;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "FILE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIRECTORY_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "USE_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = true;
+ }
+ } else if (arg == "NO_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = false;
+ }
+ } else if (arg == "FILES_MATCHING") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MatchlessFiles = false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingFiles:
+ this->Files.push_back(arg);
+ break;
+ case DoingDestination:
+ if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
+ this->Destination = arg;
+ } else {
+ this->Destination = this->Makefile->GetCurrentBinaryDirectory();
+ this->Destination += "/" + arg;
+ }
+ this->Doing = DoingNone;
+ break;
+ case DoingFilesFromDir:
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ this->FilesFromDir = arg;
+ } else {
+ this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
+ this->FilesFromDir += "/" + arg;
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
+ this->Doing = DoingNone;
+ break;
+ case DoingPattern: {
+ // Convert the pattern to a regular expression. Require a
+ // leading slash and trailing end-of-string in the matched
+ // string to make sure the pattern matches only whole file
+ // names.
+ std::string regex = "/";
+ regex += cmsys::Glob::PatternToRegex(arg, false);
+ regex += "$";
+ this->MatchRules.emplace_back(regex);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile PATTERN \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ }
+ } break;
+ case DoingRegex:
+ this->MatchRules.emplace_back(arg);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile REGEX \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsFile:
+ if (!this->CheckPermissions(arg, this->FilePermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsDir:
+ if (!this->CheckPermissions(arg, this->DirPermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsMatch:
+ if (!this->CheckPermissions(
+ arg, this->CurrentMatchRule->Properties.Permissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::Run(std::vector<std::string> const& args)
+{
+ if (!this->Parse(args)) {
+ return false;
+ }
+
+ for (std::string const& f : this->Files) {
+ std::string file;
+ if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
+ if (!this->FilesFromDir.empty()) {
+ file = this->FilesFromDir;
+ } else {
+ file = this->Makefile->GetCurrentSourceDirectory();
+ }
+ file += "/";
+ file += f;
+ } else if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
+ "to be specified as relative paths.");
+ return false;
+ } else {
+ file = f;
+ }
+
+ // Split the input file into its directory and name components.
+ std::vector<std::string> fromPathComponents;
+ cmSystemTools::SplitPath(file, fromPathComponents);
+ std::string fromName = *(fromPathComponents.end() - 1);
+ std::string fromDir = cmSystemTools::JoinPath(
+ fromPathComponents.begin(), fromPathComponents.end() - 1);
+
+ // Compute the full path to the destination file.
+ std::string toFile = this->Destination;
+ if (!this->FilesFromDir.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ if (!dir.empty()) {
+ toFile += "/";
+ toFile += dir;
+ }
+ }
+ std::string const& toName = this->ToName(fromName);
+ if (!toName.empty()) {
+ toFile += "/";
+ toFile += toName;
+ }
+
+ // Construct the full path to the source file. The file name may
+ // have been changed above.
+ std::string fromFile = fromDir;
+ if (!fromName.empty()) {
+ fromFile += "/";
+ fromFile += fromName;
+ }
+
+ if (!this->Install(fromFile, toFile)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmFileCopier::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ if (fromFile.empty()) {
+ std::ostringstream e;
+ e << "INSTALL encountered an empty string input file name.";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Collect any properties matching this file name.
+ MatchProperties match_properties = this->CollectMatchProperties(fromFile);
+
+ // Skip the file if it is excluded.
+ if (match_properties.Exclude) {
+ return true;
+ }
+
+ if (cmSystemTools::SameFile(fromFile, toFile)) {
+ return true;
+ }
+
+ std::string newFromFile = fromFile;
+ std::string newToFile = toFile;
+
+ if (this->FollowSymlinkChain &&
+ !this->InstallSymlinkChain(newFromFile, newToFile)) {
+ return false;
+ }
+
+ if (cmSystemTools::FileIsSymlink(newFromFile)) {
+ return this->InstallSymlink(newFromFile, newToFile);
+ }
+ if (cmSystemTools::FileIsDirectory(newFromFile)) {
+ return this->InstallDirectory(newFromFile, newToFile, match_properties);
+ }
+ if (cmSystemTools::FileExists(newFromFile)) {
+ return this->InstallFile(newFromFile, newToFile, match_properties);
+ }
+ return this->ReportMissing(newFromFile);
+}
+
+bool cmFileCopier::InstallSymlinkChain(std::string& fromFile,
+ std::string& toFile)
+{
+ std::string newFromFile;
+ std::string toFilePath = cmSystemTools::GetFilenamePath(toFile);
+ while (cmSystemTools::ReadSymlink(fromFile, newFromFile)) {
+ if (!cmSystemTools::FileIsFullPath(newFromFile)) {
+ std::string fromFilePath = cmSystemTools::GetFilenamePath(fromFile);
+ newFromFile = fromFilePath + "/" + newFromFile;
+ }
+
+ std::string symlinkTarget = cmSystemTools::GetFilenameName(newFromFile);
+
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ cmSystemTools::RemoveFile(toFile);
+ cmSystemTools::MakeDirectory(toFilePath);
+
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot create symlink \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ fromFile = newFromFile;
+ toFile = toFilePath + "/" + symlinkTarget;
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallSymlink(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Read the original symlink.
+ std::string symlinkTarget;
+ if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
+ std::ostringstream e;
+ e << this->Name << " cannot read symlink \"" << fromFile
+ << "\" to duplicate at \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Compare the symlink value to that at the destination if not
+ // always installing.
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ // Remove the destination file so we can always create the symlink.
+ cmSystemTools::RemoveFile(toFile);
+
+ // Create destination directory if it doesn't exist
+ cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
+
+ // Create the symlink.
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot duplicate symlink \"" << fromFile
+ << "\" at \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallFile(const std::string& fromFile,
+ const std::string& toFile,
+ MatchProperties match_properties)
+{
+ // Determine whether we will copy the file.
+ bool copy = true;
+ if (!this->Always) {
+ // If both files exist with the same time do not copy.
+ if (!this->FileTimes.DifferS(fromFile, toFile)) {
+ copy = false;
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeFile, copy);
+
+ // Copy the file.
+ if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
+ std::ostringstream e;
+ e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
+ << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Set the file modification time of the destination file.
+ if (copy && !this->Always) {
+ // Add write permission so we can set the file time.
+ // Permissions are set unconditionally below anyway.
+ mode_t perm = 0;
+ if (cmSystemTools::GetPermissions(toFile, perm)) {
+ cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
+ }
+ if (!cmFileTimes::Copy(fromFile, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set modification time on \"" << toFile
+ << "\"";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Set permissions of the destination file.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->FilePermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source file permissions be used.
+ cmSystemTools::GetPermissions(fromFile, permissions);
+ }
+ return this->SetPermissions(toFile, permissions);
+}
+
+bool cmFileCopier::InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties)
+{
+ // Inform the user about this directory installation.
+ this->ReportCopy(destination, TypeDir,
+ !cmSystemTools::FileIsDirectory(destination));
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ // Make sure the destination directory exists.
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::ostringstream e;
+ e << this->Name << " cannot make directory \"" << destination
+ << "\": " << cmSystemTools::GetLastSystemError();
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Compute the requested permissions for the destination directory.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->DirPermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source directory permissions be used.
+ cmSystemTools::GetPermissions(source, permissions);
+ }
+
+ // Compute the set of permissions required on this directory to
+ // recursively install files and subdirectories safely.
+ mode_t required_permissions =
+ mode_owner_read | mode_owner_write | mode_owner_execute;
+
+ // If the required permissions are specified it is safe to set the
+ // final permissions now. Otherwise we must add the required
+ // permissions temporarily during file installation.
+ mode_t permissions_before = 0;
+ mode_t permissions_after = 0;
+ if ((permissions & required_permissions) == required_permissions) {
+ permissions_before = permissions;
+ } else {
+ permissions_before = permissions | required_permissions;
+ permissions_after = permissions;
+ }
+
+ // Set the required permissions of the destination directory.
+ if (!this->SetPermissions(destination, permissions_before)) {
+ return false;
+ }
+
+ // Load the directory contents to traverse it recursively.
+ cmsys::Directory dir;
+ if (!source.empty()) {
+ dir.Load(source);
+ }
+ unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
+ for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
+ if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
+ strcmp(dir.GetFile(fileNum), "..") == 0)) {
+ std::string fromPath = source;
+ fromPath += "/";
+ fromPath += dir.GetFile(fileNum);
+ std::string toPath = destination;
+ toPath += "/";
+ toPath += dir.GetFile(fileNum);
+ if (!this->Install(fromPath, toPath)) {
+ return false;
+ }
+ }
+ }
+
+ // Set the requested permissions of the destination directory.
+ return this->SetPermissions(destination, permissions_after);
+}
diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h
new file mode 100644
index 000000000..a79a60b90
--- /dev/null
+++ b/Source/cmFileCopier.h
@@ -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. */
+#ifndef cmFileCopier_h
+#define cmFileCopier_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTimeCache.h"
+#include "cm_sys_stat.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+class cmMakefile;
+
+// File installation helper class.
+struct cmFileCopier
+{
+ cmFileCopier(cmFileCommand* command, const char* name = "COPY");
+ virtual ~cmFileCopier();
+
+ bool Run(std::vector<std::string> const& args);
+
+protected:
+ cmFileCommand* FileCommand;
+ cmMakefile* Makefile;
+ const char* Name;
+ bool Always;
+ cmFileTimeCache FileTimes;
+
+ // Whether to install a file not matching any expression.
+ bool MatchlessFiles;
+
+ // Permissions for files and directories installed by this object.
+ mode_t FilePermissions;
+ mode_t DirPermissions;
+
+ // Properties set by pattern and regex match rules.
+ struct MatchProperties
+ {
+ bool Exclude = false;
+ mode_t Permissions = 0;
+ };
+ struct MatchRule
+ {
+ cmsys::RegularExpression Regex;
+ MatchProperties Properties;
+ std::string RegexString;
+ MatchRule(std::string const& regex)
+ : Regex(regex)
+ , RegexString(regex)
+ {
+ }
+ };
+ std::vector<MatchRule> MatchRules;
+
+ // Get the properties from rules matching this input file.
+ MatchProperties CollectMatchProperties(const std::string& file);
+
+ bool SetPermissions(const std::string& toFile, mode_t permissions);
+
+ // Translate an argument to a permissions bit.
+ bool CheckPermissions(std::string const& arg, mode_t& permissions);
+
+ bool InstallSymlinkChain(std::string& fromFile, std::string& toFile);
+ bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
+ bool InstallFile(const std::string& fromFile, const std::string& toFile,
+ MatchProperties match_properties);
+ bool InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties);
+ virtual bool Install(const std::string& fromFile, const std::string& toFile);
+ virtual std::string const& ToName(std::string const& fromName);
+
+ enum Type
+ {
+ TypeFile,
+ TypeDir,
+ TypeLink
+ };
+ virtual void ReportCopy(const std::string&, Type, bool) {}
+ virtual bool ReportMissing(const std::string& fromFile);
+
+ MatchRule* CurrentMatchRule;
+ bool UseGivenPermissionsFile;
+ bool UseGivenPermissionsDir;
+ bool UseSourcePermissions;
+ bool FollowSymlinkChain;
+ std::string Destination;
+ std::string FilesFromDir;
+ std::vector<std::string> Files;
+ int Doing;
+
+ virtual bool Parse(std::vector<std::string> const& args);
+ enum
+ {
+ DoingNone,
+ DoingError,
+ DoingDestination,
+ DoingFilesFromDir,
+ DoingFiles,
+ DoingPattern,
+ DoingRegex,
+ DoingPermissionsFile,
+ DoingPermissionsDir,
+ DoingPermissionsMatch,
+ DoingLast1
+ };
+ virtual bool CheckKeyword(std::string const& arg);
+ virtual bool CheckValue(std::string const& arg);
+
+ void NotBeforeMatch(std::string const& arg);
+ void NotAfterMatch(std::string const& arg);
+ virtual void DefaultFilePermissions();
+ virtual void DefaultDirectoryPermissions();
+
+ bool GetDefaultDirectoryPermissions(mode_t** mode);
+};
+
+#endif
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
new file mode 100644
index 000000000..d4f76fd86
--- /dev/null
+++ b/Source/cmFileInstaller.cxx
@@ -0,0 +1,350 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileInstaller.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "cm_sys_stat.h"
+
+#include <sstream>
+
+using namespace cmFSPermissions;
+
+cmFileInstaller::cmFileInstaller(cmFileCommand* command)
+ : cmFileCopier(command, "INSTALL")
+ , InstallType(cmInstallType_FILES)
+ , Optional(false)
+ , MessageAlways(false)
+ , MessageLazy(false)
+ , MessageNever(false)
+ , DestDirLength(0)
+{
+ // Installation does not use source permissions by default.
+ this->UseSourcePermissions = false;
+ // Check whether to copy files always or only if they have changed.
+ std::string install_always;
+ if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
+ this->Always = cmSystemTools::IsOn(install_always);
+ }
+ // Get the current manifest.
+ this->Manifest =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+}
+cmFileInstaller::~cmFileInstaller()
+{
+ // Save the updated install manifest.
+ this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
+ this->Manifest.c_str());
+}
+
+void cmFileInstaller::ManifestAppend(std::string const& file)
+{
+ if (!this->Manifest.empty()) {
+ this->Manifest += ";";
+ }
+ this->Manifest += file.substr(this->DestDirLength);
+}
+
+std::string const& cmFileInstaller::ToName(std::string const& fromName)
+{
+ return this->Rename.empty() ? fromName : this->Rename;
+}
+
+void cmFileInstaller::ReportCopy(const std::string& toFile, Type type,
+ bool copy)
+{
+ if (!this->MessageNever && (copy || !this->MessageLazy)) {
+ std::string message = (copy ? "Installing: " : "Up-to-date: ");
+ message += toFile;
+ this->Makefile->DisplayStatus(message, -1);
+ }
+ if (type != TypeDir) {
+ // Add the file to the manifest.
+ this->ManifestAppend(toFile);
+ }
+}
+bool cmFileInstaller::ReportMissing(const std::string& fromFile)
+{
+ return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
+}
+bool cmFileInstaller::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Support installing from empty source to make a directory.
+ if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
+ return this->InstallDirectory(fromFile, toFile, MatchProperties());
+ }
+ return this->cmFileCopier::Install(fromFile, toFile);
+}
+
+void cmFileInstaller::DefaultFilePermissions()
+{
+ this->cmFileCopier::DefaultFilePermissions();
+ // Add execute permissions based on the target type.
+ switch (this->InstallType) {
+ case cmInstallType_SHARED_LIBRARY:
+ case cmInstallType_MODULE_LIBRARY:
+ if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
+ break;
+ }
+ CM_FALLTHROUGH;
+ case cmInstallType_EXECUTABLE:
+ case cmInstallType_PROGRAMS:
+ this->FilePermissions |= mode_owner_execute;
+ this->FilePermissions |= mode_group_execute;
+ this->FilePermissions |= mode_world_execute;
+ break;
+ default:
+ break;
+ }
+}
+
+bool cmFileInstaller::Parse(std::vector<std::string> const& args)
+{
+ if (!this->cmFileCopier::Parse(args)) {
+ return false;
+ }
+
+ if (!this->Rename.empty()) {
+ if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("INSTALL option RENAME may not be "
+ "combined with FILES_FROM_DIR.");
+ return false;
+ }
+ if (this->InstallType != cmInstallType_FILES &&
+ this->InstallType != cmInstallType_PROGRAMS) {
+ this->FileCommand->SetError("INSTALL option RENAME may be used "
+ "only with FILES or PROGRAMS.");
+ return false;
+ }
+ if (this->Files.size() > 1) {
+ this->FileCommand->SetError("INSTALL option RENAME may be used "
+ "only with one file.");
+ return false;
+ }
+ }
+
+ if (!this->HandleInstallDestination()) {
+ return false;
+ }
+
+ if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
+ (this->MessageNever ? 1 : 0)) > 1) {
+ this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
+ "MESSAGE_LAZY, and MESSAGE_NEVER "
+ "are mutually exclusive.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmFileInstaller::CheckKeyword(std::string const& arg)
+{
+ if (arg == "TYPE") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingType;
+ }
+ } else if (arg == "FILES") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFiles;
+ }
+ } else if (arg == "RENAME") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingRename;
+ }
+ } else if (arg == "OPTIONAL") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->Optional = true;
+ }
+ } else if (arg == "MESSAGE_ALWAYS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageAlways = true;
+ }
+ } else if (arg == "MESSAGE_LAZY") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageLazy = true;
+ }
+ } else if (arg == "MESSAGE_NEVER") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageNever = true;
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIR_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
+ arg == "PROPERTIES") {
+ std::ostringstream e;
+ e << "INSTALL called with old-style " << arg << " argument. "
+ << "This script was generated with an older version of CMake. "
+ << "Re-run this cmake version on your build tree.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ } else {
+ return this->cmFileCopier::CheckKeyword(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingType:
+ if (!this->GetTargetTypeFromString(arg)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingRename:
+ this->Rename = arg;
+ break;
+ default:
+ return this->cmFileCopier::CheckValue(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
+{
+ if (stype == "EXECUTABLE") {
+ this->InstallType = cmInstallType_EXECUTABLE;
+ } else if (stype == "FILE") {
+ this->InstallType = cmInstallType_FILES;
+ } else if (stype == "PROGRAM") {
+ this->InstallType = cmInstallType_PROGRAMS;
+ } else if (stype == "STATIC_LIBRARY") {
+ this->InstallType = cmInstallType_STATIC_LIBRARY;
+ } else if (stype == "SHARED_LIBRARY") {
+ this->InstallType = cmInstallType_SHARED_LIBRARY;
+ } else if (stype == "MODULE") {
+ this->InstallType = cmInstallType_MODULE_LIBRARY;
+ } else if (stype == "DIRECTORY") {
+ this->InstallType = cmInstallType_DIRECTORY;
+ } else {
+ std::ostringstream e;
+ e << "Option TYPE given unknown value \"" << stype << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmFileInstaller::HandleInstallDestination()
+{
+ std::string& destination = this->Destination;
+
+ // allow for / to be a valid destination
+ if (destination.size() < 2 && destination != "/") {
+ this->FileCommand->SetError("called with inappropriate arguments. "
+ "No DESTINATION provided or .");
+ return false;
+ }
+
+ std::string sdestdir;
+ if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
+ cmSystemTools::ConvertToUnixSlashes(sdestdir);
+ char ch1 = destination[0];
+ char ch2 = destination[1];
+ char ch3 = 0;
+ if (destination.size() > 2) {
+ ch3 = destination[2];
+ }
+ int skip = 0;
+ if (ch1 != '/') {
+ int relative = 0;
+ if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
+ ch2 == ':') {
+ // Assume windows
+ // let's do some destdir magic:
+ skip = 2;
+ if (ch3 != '/') {
+ relative = 1;
+ }
+ } else {
+ relative = 1;
+ }
+ if (relative) {
+ // This is relative path on unix or windows. Since we are doing
+ // destdir, this case does not make sense.
+ this->FileCommand->SetError(
+ "called with relative DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify "
+ "absolute path or remove DESTDIR environment variable.");
+ return false;
+ }
+ } else {
+ if (ch2 == '/') {
+ // looks like a network path.
+ std::string message =
+ "called with network path DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify local "
+ "absolute path or remove DESTDIR environment variable."
+ "\nDESTINATION=\n";
+ message += destination;
+ this->FileCommand->SetError(message);
+ return false;
+ }
+ }
+ destination = sdestdir + destination.substr(skip);
+ this->DestDirLength = int(sdestdir.size());
+ }
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ if (this->InstallType != cmInstallType_DIRECTORY) {
+ if (!cmSystemTools::FileExists(destination)) {
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::string errstring = "cannot create directory: " + destination +
+ ". Maybe need administrative privileges.";
+ this->FileCommand->SetError(errstring);
+ return false;
+ }
+ }
+ if (!cmSystemTools::FileIsDirectory(destination)) {
+ std::string errstring =
+ "INSTALL destination: " + destination + " is not a directory.";
+ this->FileCommand->SetError(errstring);
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmFileInstaller.h b/Source/cmFileInstaller.h
new file mode 100644
index 000000000..312529aa8
--- /dev/null
+++ b/Source/cmFileInstaller.h
@@ -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. */
+#ifndef cmFileInstaller_h
+#define cmFileInstaller_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileCopier.h"
+
+#include "cmInstallType.h"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+
+struct cmFileInstaller : public cmFileCopier
+{
+ cmFileInstaller(cmFileCommand* command);
+ ~cmFileInstaller() override;
+
+protected:
+ cmInstallType InstallType;
+ bool Optional;
+ bool MessageAlways;
+ bool MessageLazy;
+ bool MessageNever;
+ int DestDirLength;
+ std::string Rename;
+
+ std::string Manifest;
+ void ManifestAppend(std::string const& file);
+
+ std::string const& ToName(std::string const& fromName) override;
+
+ void ReportCopy(const std::string& toFile, Type type, bool copy) override;
+ bool ReportMissing(const std::string& fromFile) override;
+ bool Install(const std::string& fromFile,
+ const std::string& toFile) override;
+
+ bool Parse(std::vector<std::string> const& args) override;
+ enum
+ {
+ DoingType = DoingLast1,
+ DoingRename,
+ DoingLast2
+ };
+ bool CheckKeyword(std::string const& arg) override;
+ bool CheckValue(std::string const& arg) override;
+ void DefaultFilePermissions() override;
+ bool GetTargetTypeFromString(const std::string& stype);
+ bool HandleInstallDestination();
+};
+
+#endif
diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx
index 2cffa7c5b..47a223a20 100644
--- a/Source/cmFilePathChecksum.cxx
+++ b/Source/cmFilePathChecksum.cxx
@@ -74,7 +74,7 @@ std::string cmFilePathChecksum::get(std::string const& filePath) const
cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);
// Convert binary checksum to string
- return cmBase32Encoder().encodeString(&hashBytes.front(), hashBytes.size(),
+ return cmBase32Encoder().encodeString(hashBytes.data(), hashBytes.size(),
false);
}
diff --git a/Source/cmFileTime.cxx b/Source/cmFileTime.cxx
new file mode 100644
index 000000000..253457ff2
--- /dev/null
+++ b/Source/cmFileTime.cxx
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTime.h"
+
+#include <string>
+#include <time.h>
+
+// Use a platform-specific API to get file times efficiently.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+# include "cm_sys_stat.h"
+#else
+# include "cmsys/Encoding.hxx"
+# include <windows.h>
+#endif
+
+bool cmFileTime::Load(std::string const& fileName)
+{
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // POSIX version. Use the stat function.
+ struct stat fst;
+ if (::stat(fileName.c_str(), &fst) != 0) {
+ return false;
+ }
+# if CMake_STAT_HAS_ST_MTIM
+ // Nanosecond resolution
+ this->NS = fst.st_mtim.tv_sec * NsPerS + fst.st_mtim.tv_nsec;
+# elif CMake_STAT_HAS_ST_MTIMESPEC
+ // Nanosecond resolution
+ this->NS = fst.st_mtimespec.tv_sec * NsPerS + fst.st_mtimespec.tv_nsec;
+# else
+ // Second resolution
+ this->NS = fst.st_mtime * NsPerS;
+# endif
+#else
+ // Windows version. Get the modification time from extended file attributes.
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+ if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fileName).c_str(),
+ GetFileExInfoStandard, &fdata)) {
+ return false;
+ }
+
+ // Copy the file time to the output location.
+ this->NS = (static_cast<NSC>(fdata.ftLastWriteTime.dwHighDateTime) << 32) |
+ static_cast<NSC>(fdata.ftLastWriteTime.dwLowDateTime);
+ // The file time resolution is 100 ns.
+ this->NS *= 100;
+#endif
+ return true;
+}
diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h
new file mode 100644
index 000000000..d4de4e033
--- /dev/null
+++ b/Source/cmFileTime.h
@@ -0,0 +1,130 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileTime_h
+#define cmFileTime_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmFileTime
+ * \brief Abstract file modification time with support for comparison with
+ * other file modification times.
+ */
+class cmFileTime
+{
+public:
+ typedef long long NSC;
+ static constexpr NSC NsPerS = 1000000000;
+
+ cmFileTime() = default;
+ ~cmFileTime() = default;
+
+ /**
+ * @brief Loads the file time of fileName from the file system
+ * @return true on success
+ */
+ bool Load(std::string const& fileName);
+
+ /**
+ * @brief Return true if this is older than ftm
+ */
+ bool Older(cmFileTime const& ftm) const { return (this->NS - ftm.NS) < 0; }
+
+ /**
+ * @brief Return true if this is newer than ftm
+ */
+ bool Newer(cmFileTime const& ftm) const { return (ftm.NS - this->NS) < 0; }
+
+ /**
+ * @brief Return true if this is the same as ftm
+ */
+ bool Equal(cmFileTime const& ftm) const { return this->NS == ftm.NS; }
+
+ /**
+ * @brief Return true if this is not the same as ftm
+ */
+ bool Differ(cmFileTime const& ftm) const { return this->NS != ftm.NS; }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1, 0, +1 for this older, same, or newer than ftm.
+ */
+ int Compare(cmFileTime const& ftm) const
+ {
+ NSC const diff = this->NS - ftm.NS;
+ if (diff == 0) {
+ return 0;
+ }
+ return (diff < 0) ? -1 : 1;
+ }
+
+ // -- Comparison in second resolution
+
+ /**
+ * @brief Return true if this is at least a second older than ftm
+ */
+ bool OlderS(cmFileTime const& ftm) const
+ {
+ return (ftm.NS - this->NS) >= cmFileTime::NsPerS;
+ }
+
+ /**
+ * @brief Return true if this is at least a second newer than ftm
+ */
+ bool NewerS(cmFileTime const& ftm) const
+ {
+ return (this->NS - ftm.NS) >= cmFileTime::NsPerS;
+ }
+
+ /**
+ * @brief Return true if this is within the same second as ftm
+ */
+ bool EqualS(cmFileTime const& ftm) const
+ {
+ NSC diff = this->NS - ftm.NS;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff < cmFileTime::NsPerS);
+ }
+
+ /**
+ * @brief Return true if this is older or newer than ftm by at least a second
+ */
+ bool DifferS(cmFileTime const& ftm) const
+ {
+ NSC diff = this->NS - ftm.NS;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff >= cmFileTime::NsPerS);
+ }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1: this at least a second older, 0: this within the same second
+ * as ftm, +1: this at least a second newer than ftm.
+ */
+ int CompareS(cmFileTime const& ftm) const
+ {
+ NSC const diff = this->NS - ftm.NS;
+ if (diff <= -cmFileTime::NsPerS) {
+ return -1;
+ }
+ if (diff >= cmFileTime::NsPerS) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * @brief The file modification time in nanoseconds
+ */
+ NSC GetNS() const { return this->NS; }
+
+private:
+ NSC NS = 0;
+};
+
+#endif
diff --git a/Source/cmFileTimeCache.cxx b/Source/cmFileTimeCache.cxx
new file mode 100644
index 000000000..24d6bf6e1
--- /dev/null
+++ b/Source/cmFileTimeCache.cxx
@@ -0,0 +1,62 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimeCache.h"
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+cmFileTimeCache::cmFileTimeCache() = default;
+
+cmFileTimeCache::~cmFileTimeCache() = default;
+
+bool cmFileTimeCache::Load(std::string const& fileName, cmFileTime& fileTime)
+{
+ // Use the stored time if available.
+ {
+ auto fit = this->Cache.find(fileName);
+ if (fit != this->Cache.end()) {
+ fileTime = fit->second;
+ return true;
+ }
+ }
+ // Read file time from OS
+ if (!fileTime.Load(fileName)) {
+ return false;
+ }
+ // Store file time in cache
+ this->Cache[fileName] = fileTime;
+ return true;
+}
+
+bool cmFileTimeCache::Remove(std::string const& fileName)
+{
+ return (this->Cache.erase(fileName) != 0);
+}
+
+bool cmFileTimeCache::Compare(std::string const& f1, std::string const& f2,
+ int* result)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1, ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ *result = ft1.Compare(ft2);
+ return true;
+ }
+ // No comparison available. Default to the same time.
+ *result = 0;
+ return false;
+}
+
+bool cmFileTimeCache::DifferS(std::string const& f1, std::string const& f2)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1, ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ return ft1.DifferS(ft2);
+ }
+ // No comparison available. Default to different times.
+ return true;
+}
diff --git a/Source/cmFileTimeCache.h b/Source/cmFileTimeCache.h
new file mode 100644
index 000000000..4f1a3a253
--- /dev/null
+++ b/Source/cmFileTimeCache.h
@@ -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. */
+#ifndef cmFileTimeCache_h
+#define cmFileTimeCache_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTime.h" // IWYU pragma: keep
+#include <string>
+#include <unordered_map>
+
+/** \class cmFileTimeCache
+ * \brief Caches file modification times in an internal map for fast lookups.
+ */
+class cmFileTimeCache
+{
+public:
+ cmFileTimeCache();
+ ~cmFileTimeCache();
+
+ cmFileTimeCache(const cmFileTimeCache&) = delete;
+ cmFileTimeCache& operator=(const cmFileTimeCache&) = delete;
+
+ /**
+ * @brief Loads the file time from the cache or the file system.
+ * @return true on success
+ */
+ bool Load(std::string const& fileName, cmFileTime& fileTime);
+
+ /**
+ * @brief Removes a file time from the cache
+ * @return true if the file was found in the cache and removed
+ */
+ bool Remove(std::string const& fileName);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true for successful comparison and false for error.
+ *
+ * When true is returned, result has -1, 0, +1 for
+ * f1 older, same, or newer than f2.
+ */
+ bool Compare(std::string const& f1, std::string const& f2, int* result);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true unless both files exist and have modification times less
+ * than 1 second apart.
+ */
+ bool DifferS(std::string const& f1, std::string const& f2);
+
+private:
+ std::unordered_map<std::string, cmFileTime> Cache;
+};
+
+#endif
diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx
deleted file mode 100644
index 8b3911e4b..000000000
--- a/Source/cmFileTimeComparison.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmFileTimeComparison.h"
-
-#include <string>
-#include <time.h>
-#include <unordered_map>
-#include <utility>
-
-// Use a platform-specific API to get file times efficiently.
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# include "cm_sys_stat.h"
-# define cmFileTimeComparison_Type struct stat
-#else
-# include "cmsys/Encoding.hxx"
-# include <windows.h>
-# define cmFileTimeComparison_Type FILETIME
-#endif
-
-class cmFileTimeComparisonInternal
-{
-public:
- // Internal comparison method.
- inline bool FileTimeCompare(const std::string& f1, const std::string& f2,
- int* result);
-
- bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-private:
- typedef std::unordered_map<std::string, cmFileTimeComparison_Type>
- FileStatsMap;
- FileStatsMap Files;
-
- // Internal methods to lookup and compare modification times.
- inline bool Stat(const std::string& fname, cmFileTimeComparison_Type* st);
- inline int Compare(cmFileTimeComparison_Type* st1,
- cmFileTimeComparison_Type* st2);
- inline bool TimesDiffer(cmFileTimeComparison_Type* st1,
- cmFileTimeComparison_Type* st2);
-};
-
-bool cmFileTimeComparisonInternal::Stat(const std::string& fname,
- cmFileTimeComparison_Type* st)
-{
- // Use the stored time if available.
- cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
- this->Files.find(fname);
- if (fit != this->Files.end()) {
- *st = fit->second;
- return true;
- }
-
-#if !defined(_WIN32) || defined(__CYGWIN__)
- // POSIX version. Use the stat function.
- int res = ::stat(fname.c_str(), st);
- if (res != 0) {
- return false;
- }
-#else
- // Windows version. Get the modification time from extended file
- // attributes.
- WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fname).c_str(),
- GetFileExInfoStandard, &fdata)) {
- return false;
- }
-
- // Copy the file time to the output location.
- *st = fdata.ftLastWriteTime;
-#endif
-
- // Store the time for future use.
- this->Files[fname] = *st;
- return true;
-}
-
-cmFileTimeComparison::cmFileTimeComparison()
-{
- this->Internals = new cmFileTimeComparisonInternal;
-}
-
-cmFileTimeComparison::~cmFileTimeComparison()
-{
- delete this->Internals;
-}
-
-bool cmFileTimeComparison::FileTimeCompare(const std::string& f1,
- const std::string& f2, int* result)
-{
- return this->Internals->FileTimeCompare(f1, f2, result);
-}
-
-bool cmFileTimeComparison::FileTimesDiffer(const std::string& f1,
- const std::string& f2)
-{
- return this->Internals->FileTimesDiffer(f1, f2);
-}
-
-int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1,
- cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# if CMake_STAT_HAS_ST_MTIM
- // Compare using nanosecond resolution.
- if (s1->st_mtim.tv_sec < s2->st_mtim.tv_sec) {
- return -1;
- }
- if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) {
- return 1;
- }
- if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) {
- return -1;
- }
- if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) {
- return 1;
- }
-# elif CMake_STAT_HAS_ST_MTIMESPEC
- // Compare using nanosecond resolution.
- if (s1->st_mtimespec.tv_sec < s2->st_mtimespec.tv_sec) {
- return -1;
- }
- if (s1->st_mtimespec.tv_sec > s2->st_mtimespec.tv_sec) {
- return 1;
- }
- if (s1->st_mtimespec.tv_nsec < s2->st_mtimespec.tv_nsec) {
- return -1;
- }
- if (s1->st_mtimespec.tv_nsec > s2->st_mtimespec.tv_nsec) {
- return 1;
- }
-# else
- // Compare using 1 second resolution.
- if (s1->st_mtime < s2->st_mtime) {
- return -1;
- }
- if (s1->st_mtime > s2->st_mtime) {
- return 1;
- }
-# endif
- // Files have the same time.
- return 0;
-#else
- // Compare using system-provided function.
- return (int)CompareFileTime(s1, s2);
-#endif
-}
-
-bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1,
- cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# if CMake_STAT_HAS_ST_MTIM
- // Times are integers in units of 1ns.
- long long bil = 1000000000;
- long long t1 = s1->st_mtim.tv_sec * bil + s1->st_mtim.tv_nsec;
- long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec;
- if (t1 < t2) {
- return (t2 - t1) >= bil;
- }
- if (t2 < t1) {
- return (t1 - t2) >= bil;
- }
- return false;
-# elif CMake_STAT_HAS_ST_MTIMESPEC
- // Times are integers in units of 1ns.
- long long bil = 1000000000;
- long long t1 = s1->st_mtimespec.tv_sec * bil + s1->st_mtimespec.tv_nsec;
- long long t2 = s2->st_mtimespec.tv_sec * bil + s2->st_mtimespec.tv_nsec;
- if (t1 < t2) {
- return (t2 - t1) >= bil;
- }
- if (t2 < t1) {
- return (t1 - t2) >= bil;
- }
- return false;
-# else
- // Times are integers in units of 1s.
- if (s1->st_mtime < s2->st_mtime) {
- return (s2->st_mtime - s1->st_mtime) >= 1;
- }
- if (s1->st_mtime > s2->st_mtime) {
- return (s1->st_mtime - s2->st_mtime) >= 1;
- }
- return false;
-# endif
-#else
- // Times are integers in units of 100ns.
- LARGE_INTEGER t1;
- LARGE_INTEGER t2;
- t1.LowPart = s1->dwLowDateTime;
- t1.HighPart = s1->dwHighDateTime;
- t2.LowPart = s2->dwLowDateTime;
- t2.HighPart = s2->dwHighDateTime;
- if (t1.QuadPart < t2.QuadPart) {
- return (t2.QuadPart - t1.QuadPart) >= static_cast<LONGLONG>(10000000);
- } else if (t2.QuadPart < t1.QuadPart) {
- return (t1.QuadPart - t2.QuadPart) >= static_cast<LONGLONG>(10000000);
- } else {
- return false;
- }
-#endif
-}
-
-bool cmFileTimeComparisonInternal::FileTimeCompare(const std::string& f1,
- const std::string& f2,
- int* result)
-{
- // Get the modification time for each file.
- cmFileTimeComparison_Type s1;
- cmFileTimeComparison_Type s2;
- if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
- // Compare the two modification times.
- *result = this->Compare(&s1, &s2);
- return true;
- }
- // No comparison available. Default to the same time.
- *result = 0;
- return false;
-}
-
-bool cmFileTimeComparisonInternal::FileTimesDiffer(const std::string& f1,
- const std::string& f2)
-{
- // Get the modification time for each file.
- cmFileTimeComparison_Type s1;
- cmFileTimeComparison_Type s2;
- if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
- // Compare the two modification times.
- return this->TimesDiffer(&s1, &s2);
- }
- // No comparison available. Default to different times.
- return true;
-}
diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h
deleted file mode 100644
index 5f74e3499..000000000
--- a/Source/cmFileTimeComparison.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmFileTimeComparison_h
-#define cmFileTimeComparison_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-
-class cmFileTimeComparisonInternal;
-
-/** \class cmFileTimeComparison
- * \brief Helper class for comparing file modification times.
- *
- * Compare file modification times or test if file modification times differ.
- */
-class cmFileTimeComparison
-{
-public:
- cmFileTimeComparison();
- ~cmFileTimeComparison();
-
- /**
- * Compare file modification times.
- * Return true for successful comparison and false for error.
- * When true is returned, result has -1, 0, +1 for
- * f1 older, same, or newer than f2.
- */
- bool FileTimeCompare(const std::string& f1, const std::string& f2,
- int* result);
-
- /**
- * Compare file modification times. Return true unless both files
- * exist and have modification times less than 1 second apart.
- */
- bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-protected:
- cmFileTimeComparisonInternal* Internals;
-};
-
-#endif
diff --git a/Source/cmFileTimes.cxx b/Source/cmFileTimes.cxx
new file mode 100644
index 000000000..fd4f6797f
--- /dev/null
+++ b/Source/cmFileTimes.cxx
@@ -0,0 +1,127 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimes.h"
+
+#include "cmAlgorithms.h"
+#include "cm_sys_stat.h"
+
+#include <utility>
+
+#if defined(_WIN32)
+# include "cmSystemTools.h"
+# include <windows.h>
+#else
+# include <utime.h>
+#endif
+
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
+# include <io.h>
+#endif
+
+#ifdef _WIN32
+class cmFileTimes::WindowsHandle
+{
+public:
+ WindowsHandle(HANDLE h)
+ : handle_(h)
+ {
+ }
+ ~WindowsHandle()
+ {
+ if (this->handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(this->handle_);
+ }
+ }
+ explicit operator bool() const
+ {
+ return this->handle_ != INVALID_HANDLE_VALUE;
+ }
+ bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; }
+ operator HANDLE() const { return this->handle_; }
+
+private:
+ HANDLE handle_;
+};
+#endif
+
+class cmFileTimes::Times
+{
+public:
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILETIME timeCreation;
+ FILETIME timeLastAccess;
+ FILETIME timeLastWrite;
+#else
+ struct utimbuf timeBuf;
+#endif
+};
+
+cmFileTimes::cmFileTimes() = default;
+cmFileTimes::cmFileTimes(std::string const& fileName)
+{
+ Load(fileName);
+}
+cmFileTimes::~cmFileTimes() = default;
+
+bool cmFileTimes::Load(std::string const& fileName)
+{
+ std::unique_ptr<Times> ptr;
+ if (IsValid()) {
+ // Invalidate this and re-use times
+ ptr.swap(this->times);
+ } else {
+ ptr = cm::make_unique<Times>();
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle =
+ CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ if (!GetFileTime(handle, &ptr->timeCreation, &ptr->timeLastAccess,
+ &ptr->timeLastWrite)) {
+ return false;
+ }
+#else
+ struct stat st;
+ if (stat(fileName.c_str(), &st) < 0) {
+ return false;
+ }
+ ptr->timeBuf.actime = st.st_atime;
+ ptr->timeBuf.modtime = st.st_mtime;
+#endif
+ // Accept times
+ this->times = std::move(ptr);
+ return true;
+}
+
+bool cmFileTimes::Store(std::string const& fileName) const
+{
+ if (!IsValid()) {
+ return false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle = CreateFileW(
+ cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ return SetFileTime(handle, &this->times->timeCreation,
+ &this->times->timeLastAccess,
+ &this->times->timeLastWrite) != 0;
+#else
+ return utime(fileName.c_str(), &this->times->timeBuf) >= 0;
+#endif
+}
+
+bool cmFileTimes::Copy(std::string const& fromFile, std::string const& toFile)
+{
+ cmFileTimes fileTimes;
+ return (fileTimes.Load(fromFile) && fileTimes.Store(toFile));
+}
diff --git a/Source/cmFileTimes.h b/Source/cmFileTimes.h
new file mode 100644
index 000000000..cbf0fe20a
--- /dev/null
+++ b/Source/cmFileTimes.h
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileTimes_h
+#define cmFileTimes_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <memory> // IWYU pragma: keep
+#include <string>
+
+/** \class cmFileTimes
+ * \brief Loads and stores file times.
+ */
+class cmFileTimes
+{
+public:
+ cmFileTimes();
+ //! Calls Load()
+ cmFileTimes(std::string const& fileName);
+ ~cmFileTimes();
+
+ //! @return true, if file times were loaded successfully
+ bool IsValid() const { return (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())
+ bool Store(std::string const& fileName) const;
+
+ //! Copies the file times of @a fromFile to @a toFile
+ static bool Copy(std::string const& fromFile, std::string const& toFile);
+
+private:
+#ifdef _WIN32
+ class WindowsHandle;
+#endif
+ class Times;
+ std::unique_ptr<Times> times;
+};
+
+#endif
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 425546a83..e5908028f 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -4,12 +4,12 @@
#include <deque>
#include <iostream>
-#include <iterator>
#include <map>
#include <stddef.h>
#include "cmAlgorithms.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSearchPath.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -146,8 +146,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
std::vector<std::string> shortArgs = this->Names;
this->Names.clear(); // clear out any values in Names
this->Names.push_back(shortArgs[0]);
- this->UserGuessArgs.insert(this->UserGuessArgs.end(),
- shortArgs.begin() + 1, shortArgs.end());
+ cmAppend(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end());
}
this->ExpandPaths();
@@ -205,11 +204,9 @@ void cmFindBase::FillPackageRootPath()
cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
// Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
- for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths =
- this->Makefile->FindPackageRootPathStack.rbegin();
- pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
- ++pkgPaths) {
- paths.AddPrefixPaths(*pkgPaths);
+ for (std::vector<std::string> const& pkgPaths :
+ cmReverseRange(this->Makefile->FindPackageRootPathStack)) {
+ paths.AddPrefixPaths(pkgPaths);
}
paths.AddSuffixes(this->SearchPathSuffixes);
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
index 78be64e09..954558f4d 100644
--- a/Source/cmFindCommon.cxx
+++ b/Source/cmFindCommon.cxx
@@ -6,6 +6,7 @@
#include <string.h>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -221,7 +222,7 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
// If searching both rooted and unrooted paths add the original
// paths again.
if (this->FindRootPathMode == RootPathModeBoth) {
- paths.insert(paths.end(), unrootedPaths.begin(), unrootedPaths.end());
+ cmAppend(paths, unrootedPaths);
}
}
@@ -310,7 +311,7 @@ void cmFindCommon::AddPathSuffix(std::string const& arg)
void AddTrailingSlash(std::string& s)
{
- if (!s.empty() && *s.rbegin() != '/') {
+ if (!s.empty() && s.back() != '/') {
s += '/';
}
}
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index c2e0712ff..1d4a8edd6 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -23,6 +23,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSearchPath.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -466,7 +467,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
// Allocate a PACKAGE_ROOT_PATH for the current find_package call.
this->Makefile->FindPackageRootPathStack.emplace_back();
std::vector<std::string>& rootPaths =
- *this->Makefile->FindPackageRootPathStack.rbegin();
+ this->Makefile->FindPackageRootPathStack.back();
// Add root paths from <PackageName>_ROOT CMake and environment variables,
// subject to CMP0074.
@@ -497,57 +498,85 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
this->SetModuleVariables(components);
// See if there is a Find<PackageName>.cmake module.
- if (this->UseFindModules) {
- bool foundModule = false;
- if (!this->FindModule(foundModule)) {
- this->AppendSuccessInformation();
- return false;
+ bool loadedPackage = false;
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ } else {
+ if (this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // The package was not loaded. Report errors.
+ HandlePackageMode(HandlePackageModeType::Module);
+ }
}
- if (foundModule) {
- this->AppendSuccessInformation();
- return true;
+ } else {
+ if (this->UseFindModules && this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // Handle CMAKE_FIND_PACKAGE_WARN_NO_MODULE (warn when CONFIG mode is
+ // implicitly assumed)
+ if (this->UseFindModules && this->UseConfigFiles &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) {
+ std::ostringstream aw;
+ if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) {
+ aw << "find_package called without either MODULE or CONFIG option "
+ "and "
+ "no Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add MODULE to exclusively request Module mode and fail if "
+ "Find"
+ << this->Name
+ << ".cmake is missing. "
+ "Add CONFIG to exclusively request Config mode and search for "
+ "a "
+ "package configuration file provided by "
+ << this->Name << " (" << this->Name << "Config.cmake or "
+ << cmSystemTools::LowerCase(this->Name) << "-config.cmake). ";
+ } else {
+ aw << "find_package called without NO_MODULE option and no "
+ "Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add NO_MODULE to exclusively request Config mode and search "
+ "for a "
+ "package configuration file provided by "
+ << this->Name << " (" << this->Name << "Config.cmake or "
+ << cmSystemTools::LowerCase(this->Name)
+ << "-config.cmake). "
+ "Otherwise make Find"
+ << this->Name
+ << ".cmake available in "
+ "CMAKE_MODULE_PATH.";
+ }
+ aw << "\n"
+ "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
+ "warning.)";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+ }
+
+ if (this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ }
}
}
- if (this->UseFindModules && this->UseConfigFiles &&
- this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) {
- std::ostringstream aw;
- if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) {
- aw << "find_package called without either MODULE or CONFIG option and "
- "no Find"
- << this->Name
- << ".cmake module is in CMAKE_MODULE_PATH. "
- "Add MODULE to exclusively request Module mode and fail if "
- "Find"
- << this->Name
- << ".cmake is missing. "
- "Add CONFIG to exclusively request Config mode and search for a "
- "package configuration file provided by "
- << this->Name << " (" << this->Name << "Config.cmake or "
- << cmSystemTools::LowerCase(this->Name) << "-config.cmake). ";
- } else {
- aw
- << "find_package called without NO_MODULE option and no "
- "Find"
- << this->Name
- << ".cmake module is in CMAKE_MODULE_PATH. "
- "Add NO_MODULE to exclusively request Config mode and search for a "
- "package configuration file provided by "
- << this->Name << " (" << this->Name << "Config.cmake or "
- << cmSystemTools::LowerCase(this->Name)
- << "-config.cmake). "
- "Otherwise make Find"
- << this->Name
- << ".cmake available in "
- "CMAKE_MODULE_PATH.";
- }
- aw << "\n"
- "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this warning.)";
- this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
- }
-
- // No find module. Assume the project has a CMake config file. Use
- // a <PackageName>_DIR cache variable to locate it.
+ this->AppendSuccessInformation();
+ return loadedPackage;
+}
+
+bool cmFindPackageCommand::FindPackageUsingModuleMode()
+{
+ bool foundModule = false;
+ if (!this->FindModule(foundModule)) {
+ return false;
+ }
+ return foundModule;
+}
+
+bool cmFindPackageCommand::FindPackageUsingConfigMode()
+{
this->Variable = this->Name;
this->Variable += "_DIR";
@@ -579,9 +608,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
this->IgnoredPaths.insert(ignored.begin(), ignored.end());
// Find and load the package.
- bool result = this->HandlePackageMode();
- this->AppendSuccessInformation();
- return result;
+ return this->HandlePackageMode(HandlePackageModeType::Config);
}
void cmFindPackageCommand::SetModuleVariables(const std::string& components)
@@ -700,7 +727,8 @@ bool cmFindPackageCommand::FindModule(bool& found)
return true;
}
-bool cmFindPackageCommand::HandlePackageMode()
+bool cmFindPackageCommand::HandlePackageMode(
+ HandlePackageModeType handlePackageModeType)
{
this->ConsideredConfigs.clear();
@@ -795,6 +823,13 @@ bool cmFindPackageCommand::HandlePackageMode()
}
}
+ if (this->UseFindModules && !found &&
+ handlePackageModeType == HandlePackageModeType::Config &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ // Config mode failed. Allow Module case.
+ result = false;
+ }
+
// package not found
if (result && !found) {
// warn if package required or neither quiet nor in config mode
@@ -827,10 +862,10 @@ bool cmFindPackageCommand::HandlePackageMode()
<< " requested version \"" << this->Version << "\".\n"
<< "The following configuration files were considered but not "
"accepted:\n";
- for (std::vector<ConfigFileInfo>::const_iterator i =
- this->ConsideredConfigs.begin();
- i != duplicate_end; ++i) {
- e << " " << i->filename << ", version: " << i->version << "\n";
+
+ for (ConfigFileInfo const& info :
+ cmMakeRange(this->ConsideredConfigs.cbegin(), duplicate_end)) {
+ e << " " << info.filename << ", version: " << info.version << "\n";
}
} else {
std::string requestedVersionString;
@@ -911,7 +946,7 @@ bool cmFindPackageCommand::HandlePackageMode()
std::ostringstream aw;
aw << "Could NOT find " << this->Name << " (missing: " << this->Name
<< "_DIR)";
- this->Makefile->DisplayStatus(aw.str().c_str(), -1);
+ this->Makefile->DisplayStatus(aw.str(), -1);
}
}
@@ -1372,6 +1407,9 @@ public:
cmSystemTools::RemoveFile(this->File);
}
}
+ cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+ cmFindPackageCommandHoldFile& operator=(
+ const cmFindPackageCommandHoldFile&) = delete;
void Release() { this->File = nullptr; }
};
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index a11d25304..316ca0f3d 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -90,6 +90,9 @@ private:
static PathLabel SystemRegistry;
};
+ bool FindPackageUsingModuleMode();
+ bool FindPackageUsingConfigMode();
+
// Add additional search path labels and groups not present in the
// parent class
void AppendSearchPathGroups();
@@ -100,7 +103,14 @@ private:
bool FindModule(bool& found);
void AddFindDefinition(const std::string& var, const char* val);
void RestoreFindDefinitions();
- bool HandlePackageMode();
+
+ enum /*class*/ HandlePackageModeType
+ {
+ Module,
+ Config
+ };
+ bool HandlePackageMode(HandlePackageModeType type);
+
bool FindConfig();
bool FindPrefixedConfig();
bool FindFrameworkConfig();
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index e359deff9..08003eb71 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -11,6 +11,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
@@ -48,12 +49,10 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
if (mf.GetDefinition(this->Args[0])) {
oldDef = mf.GetDefinition(this->Args[0]);
}
- std::vector<std::string>::const_iterator j = this->Args.begin();
- ++j;
- for (; j != this->Args.end(); ++j) {
+ for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
// set the variable to the loop value
- mf.AddDefinition(this->Args[0], j->c_str());
+ mf.AddDefinition(this->Args[0], arg.c_str());
// Invoke all the functions that were collected in the block.
cmExecutionStatus status;
for (cmListFileFunction const& func : this->Functions) {
diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h
index 076234035..6a33be571 100644
--- a/Source/cmFortranParser.h
+++ b/Source/cmFortranParser.h
@@ -141,6 +141,9 @@ struct cmFortranParser_s
std::set<std::string> defines, cmFortranSourceInfo& info);
~cmFortranParser_s();
+ cmFortranParser_s(const cmFortranParser_s&) = delete;
+ cmFortranParser_s& operator=(const cmFortranParser_s&) = delete;
+
bool FindIncludeFile(const char* dir, const char* includeName,
std::string& fileName);
diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx
index 18e3c107d..e8b1da83c 100644
--- a/Source/cmFortranParserImpl.cxx
+++ b/Source/cmFortranParserImpl.cxx
@@ -79,7 +79,13 @@ std::string cmFortranParser_s::ModName(std::string const& mod_name) const
std::string cmFortranParser_s::SModName(std::string const& mod_name,
std::string const& sub_name) const
{
- return mod_name + this->Compiler.SModSep + sub_name + this->Compiler.SModExt;
+ std::string const& SModExt =
+ this->Compiler.SModExt.empty() ? ".mod" : this->Compiler.SModExt;
+ // An empty separator means that the compiler does not use a prefix.
+ if (this->Compiler.SModSep.empty()) {
+ return sub_name + SModExt;
+ }
+ return mod_name + this->Compiler.SModSep + sub_name + SModExt;
}
bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname)
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 264a3385c..9067a5f64 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -8,6 +8,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
// define the class for function commands
@@ -176,7 +177,7 @@ bool cmFunctionCommand::InitialPass(std::vector<std::string> const& args,
// create a function blocker
cmFunctionFunctionBlocker* f = new cmFunctionFunctionBlocker();
- f->Args.insert(f->Args.end(), args.begin(), args.end());
+ cmAppend(f->Args, args);
this->Makefile->AddFunctionBlocker(f);
return true;
}
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 4fe15874d..2f47788f8 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -29,8 +29,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
{
// Check if the file opened.
if (!*this && !quiet) {
- cmSystemTools::Error("Cannot open file for write: ",
- this->TempName.c_str());
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
cmSystemTools::ReportLastSystemError("");
}
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -68,8 +67,7 @@ cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name,
// Check if the file opened.
if (!*this && !quiet) {
- cmSystemTools::Error("Cannot open file for write: ",
- this->TempName.c_str());
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
cmSystemTools::ReportLastSystemError("");
}
return *this;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index f9a6d6454..744201899 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -34,20 +34,16 @@ std::string GeneratorExpressionContent::ProcessArbitraryContent(
std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator pend =
this->ParamChildren.end();
for (; pit != pend; ++pit) {
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- pit->begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- pit->end();
- for (; it != end; ++it) {
+ for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
if (node->RequiresLiteralInput()) {
- if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) {
+ if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires literal input.");
return std::string();
}
}
- result += (*it)->Evaluate(context, dagChecker);
+ result += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -70,12 +66,9 @@ std::string GeneratorExpressionContent::Evaluate(
{
std::string identifier;
{
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- this->IdentifierChildren.begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- this->IdentifierChildren.end();
- for (; it != end; ++it) {
- identifier += (*it)->Evaluate(context, dagChecker);
+ for (cmGeneratorExpressionEvaluator* pExprEval :
+ this->IdentifierChildren) {
+ identifier += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -138,12 +131,8 @@ std::string GeneratorExpressionContent::EvaluateParameters(
return std::string();
}
std::string parameter;
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- pit->begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- pit->end();
- for (; it != end; ++it) {
- parameter += (*it)->Evaluate(context, dagChecker);
+ for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
+ parameter += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -177,9 +166,13 @@ std::string GeneratorExpressionContent::EvaluateParameters(
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires at least one parameter.");
- }
- if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
- parameters.size() > 1) {
+ } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
+ parameters.size() < 2) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires at least two parameters.");
+ } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
+ parameters.size() > 1) {
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires one or zero parameters.");
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 70c80c90d..a60c75cd9 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -15,16 +15,23 @@
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
#include "cmake.h"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
+
#include <algorithm>
#include <assert.h>
#include <errno.h>
+#include <iterator>
#include <map>
#include <memory> // IWYU pragma: keep
#include <set>
@@ -92,38 +99,42 @@ static const struct OneNode buildInterfaceNode;
static const struct ZeroNode installInterfaceNode;
-#define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
- static const struct OP##Node : public cmGeneratorExpressionNode \
- { \
- OP##Node() {} /* NOLINT(modernize-use-equals-default) */ \
- virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
- \
- std::string Evaluate(const std::vector<std::string>& parameters, \
- cmGeneratorExpressionContext* context, \
- const GeneratorExpressionContent* content, \
- cmGeneratorExpressionDAGChecker*) const \
- { \
- std::vector<std::string>::const_iterator it = parameters.begin(); \
- const std::vector<std::string>::const_iterator end = parameters.end(); \
- for (; it != end; ++it) { \
- if (*it == #FAILURE_VALUE) { \
- return #FAILURE_VALUE; \
- } \
- if (*it != #SUCCESS_VALUE) { \
- reportError(context, content->GetOriginalExpression(), \
- "Parameters to $<" #OP \
- "> must resolve to either '0' or '1'."); \
- return std::string(); \
- } \
- } \
- return #SUCCESS_VALUE; \
- } \
- } OPNAME;
-
-BOOLEAN_OP_NODE(andNode, AND, 1, 0)
-BOOLEAN_OP_NODE(orNode, OR, 0, 1)
-
-#undef BOOLEAN_OP_NODE
+struct BooleanOpNode : public cmGeneratorExpressionNode
+{
+ BooleanOpNode(const char* op_, const char* successVal_,
+ const char* failureVal_)
+ : op(op_)
+ , successVal(successVal_)
+ , failureVal(failureVal_)
+ {
+ }
+
+ int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const override
+ {
+ for (std::string const& param : parameters) {
+ if (param == this->failureVal) {
+ return this->failureVal;
+ }
+ if (param != this->successVal) {
+ std::ostringstream e;
+ e << "Parameters to $<" << this->op;
+ e << "> must resolve to either '0' or '1'.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ }
+ return this->successVal;
+ }
+
+ const char *const op, *const successVal, *const failureVal;
+};
+
+static const BooleanOpNode andNode("AND", "1", "0"), orNode("OR", "0", "1");
static const struct NotNode : public cmGeneratorExpressionNode
{
@@ -135,13 +146,13 @@ static const struct NotNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- if (*parameters.begin() != "0" && *parameters.begin() != "1") {
+ if (parameters.front() != "0" && parameters.front() != "1") {
reportError(
context, content->GetOriginalExpression(),
"$<NOT> parameter must resolve to exactly one '0' or '1' value.");
return std::string();
}
- return *parameters.begin() == "0" ? "1" : "0";
+ return parameters.front() == "0" ? "1" : "0";
}
} notNode;
@@ -157,7 +168,7 @@ static const struct BoolNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return !cmSystemTools::IsOff(*parameters.begin()) ? "1" : "0";
+ return !cmSystemTools::IsOff(parameters.front()) ? "1" : "0";
}
} boolNode;
@@ -194,7 +205,7 @@ static const struct StrEqualNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return *parameters.begin() == parameters[1] ? "1" : "0";
+ return parameters.front() == parameters[1] ? "1" : "0";
}
} strEqualNode;
@@ -210,69 +221,44 @@ static const struct EqualNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- char* pEnd;
-
- int base = 0;
- bool flipSign = false;
-
- const char* lhs = parameters[0].c_str();
- if (cmHasLiteralPrefix(lhs, "0b") || cmHasLiteralPrefix(lhs, "0B")) {
- base = 2;
- lhs += 2;
- }
- if (cmHasLiteralPrefix(lhs, "-0b") || cmHasLiteralPrefix(lhs, "-0B")) {
- base = 2;
- lhs += 3;
- flipSign = true;
- }
- if (cmHasLiteralPrefix(lhs, "+0b") || cmHasLiteralPrefix(lhs, "+0B")) {
- base = 2;
- lhs += 3;
- }
-
- long lnum = strtol(lhs, &pEnd, base);
- if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
- reportError(context, content->GetOriginalExpression(),
- "$<EQUAL> parameter " + parameters[0] +
- " is not a valid integer.");
- return std::string();
- }
-
- if (flipSign) {
- lnum = -lnum;
+ long numbers[2];
+ for (int i = 0; i < 2; ++i) {
+ if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<EQUAL> parameter " + parameters[i] +
+ " is not a valid integer.");
+ return {};
+ }
}
+ return numbers[0] == numbers[1] ? "1" : "0";
+ }
- base = 0;
- flipSign = false;
+ static bool ParameterToLong(const char* param, long* outResult)
+ {
+ const char isNegative = param[0] == '-';
- const char* rhs = parameters[1].c_str();
- if (cmHasLiteralPrefix(rhs, "0b") || cmHasLiteralPrefix(rhs, "0B")) {
- base = 2;
- rhs += 2;
- }
- if (cmHasLiteralPrefix(rhs, "-0b") || cmHasLiteralPrefix(rhs, "-0B")) {
+ int base = 0;
+ if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
base = 2;
- rhs += 3;
- flipSign = true;
- }
- if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) {
+ param += 2;
+ } else if (cmHasLiteralPrefix(param, "-0b") ||
+ cmHasLiteralPrefix(param, "-0B") ||
+ cmHasLiteralPrefix(param, "+0b") ||
+ cmHasLiteralPrefix(param, "+0B")) {
base = 2;
- rhs += 3;
+ param += 3;
}
- long rnum = strtol(rhs, &pEnd, base);
- if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
- reportError(context, content->GetOriginalExpression(),
- "$<EQUAL> parameter " + parameters[1] +
- " is not a valid integer.");
- return std::string();
+ char* pEnd;
+ long result = strtol(param, &pEnd, base);
+ if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
+ return false;
}
-
- if (flipSign) {
- rnum = -rnum;
+ if (isNegative && result > 0) {
+ result *= -1;
}
-
- return lnum == rnum ? "1" : "0";
+ *outResult = result;
+ return true;
}
} equalNode;
@@ -326,6 +312,79 @@ static const struct InListNode : public cmGeneratorExpressionNode
}
} inListNode;
+static const struct FilterNode : public cmGeneratorExpressionNode
+{
+ FilterNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 3; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 3) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> expression requires three parameters");
+ return {};
+ }
+
+ if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
+ return {};
+ }
+
+ const bool exclude = parameters[1] == "EXCLUDE";
+
+ cmsys::RegularExpression re;
+ if (!re.compile(parameters[2])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> failed to compile regex");
+ return {};
+ }
+
+ std::vector<std::string> values, result;
+ cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+ std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
+ [&re, exclude](std::string const& input) {
+ return exclude ^ re.find(input);
+ });
+ return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
+ }
+} filterNode;
+
+static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
+{
+ RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 1) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<REMOVE_DUPLICATES:...> expression requires one parameter");
+ }
+
+ std::vector<std::string> values;
+ cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+ auto valuesEnd = cmRemoveDuplicates(values);
+ auto valuesBegin = values.cbegin();
+ return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
+ }
+
+} removeDuplicatesNode;
+
static const struct TargetExistsNode : public cmGeneratorExpressionNode
{
TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
@@ -546,9 +605,10 @@ static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
}
} makeCIdentifierNode;
-static const struct Angle_RNode : public cmGeneratorExpressionNode
+template <char C>
+struct CharacterNode : public cmGeneratorExpressionNode
{
- Angle_RNode() {} // NOLINT(modernize-use-equals-default)
+ CharacterNode() {} // NOLINT(modernize-use-equals-default)
int NumExpectedParameters() const override { return 0; }
@@ -558,47 +618,39 @@ static const struct Angle_RNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return ">";
+ return { C };
}
-} angle_rNode;
+};
+static const CharacterNode<'>'> angle_rNode;
+static const CharacterNode<','> commaNode;
+static const CharacterNode<';'> semicolonNode;
-static const struct CommaNode : public cmGeneratorExpressionNode
+struct CompilerIdNode : public cmGeneratorExpressionNode
{
- CommaNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 0; }
-
- std::string Evaluate(
- const std::vector<std::string>& /*parameters*/,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ CompilerIdNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
{
- return ",";
}
-} commaNode;
-static const struct SemicolonNode : public cmGeneratorExpressionNode
-{
- SemicolonNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 0; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
- const std::vector<std::string>& /*parameters*/,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
{
- return ";";
+ if (!context->HeadTarget) {
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_ID> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->CompilerLanguage);
}
-} semicolonNode;
-
-struct CompilerIdNode : public cmGeneratorExpressionNode
-{
- CompilerIdNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
@@ -612,89 +664,58 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
if (parameters.empty()) {
return compilerId;
}
- static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
- if (!compilerIdValidator.find(*parameters.begin())) {
- reportError(context, content->GetOriginalExpression(),
- "Expression syntax not recognized.");
- return std::string();
- }
if (compilerId.empty()) {
return parameters.front().empty() ? "1" : "0";
}
+ static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
- if (strcmp(parameters.begin()->c_str(), compilerId.c_str()) == 0) {
- return "1";
- }
+ for (auto& param : parameters) {
- if (cmsysString_strcasecmp(parameters.begin()->c_str(),
- compilerId.c_str()) == 0) {
- switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
- case cmPolicies::WARN: {
- std::ostringstream e;
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
- context->LG->GetCMakeInstance()->IssueMessage(
- MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
- CM_FALLTHROUGH;
+ if (!compilerIdValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+
+ if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
+ return "1";
+ }
+
+ if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) {
+ switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
+ context->LG->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ return "1";
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
}
- case cmPolicies::OLD:
- return "1";
- case cmPolicies::NEW:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::REQUIRED_IF_USED:
- break;
}
}
return "0";
}
+
+ const char* const CompilerLanguage;
};
-static const struct CCompilerIdNode : public CompilerIdNode
-{
- CCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
+static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
+ cudaCompilerIdNode("CUDA"), fortranCompilerIdNode("Fortran");
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<C_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "C");
- }
-} cCompilerIdNode;
-
-static const struct CXXCompilerIdNode : public CompilerIdNode
+struct CompilerVersionNode : public cmGeneratorExpressionNode
{
- CXXCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
+ CompilerVersionNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
{
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<CXX_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "CXX");
}
-} cxxCompilerIdNode;
-static const struct FortranCompilerIdNode : public CompilerIdNode
-{
- FortranCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
+ int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -703,22 +724,16 @@ static const struct FortranCompilerIdNode : public CompilerIdNode
cmGeneratorExpressionDAGChecker* dagChecker) const override
{
if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<Fortran_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_VERSION> may only be used with binary targets. It "
+ "may not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
}
return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "Fortran");
+ this->CompilerLanguage);
}
-} fortranCompilerIdNode;
-
-struct CompilerVersionNode : public cmGeneratorExpressionNode
-{
- CompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
@@ -734,94 +749,34 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
}
static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
- if (!compilerIdValidator.find(*parameters.begin())) {
+ if (!compilerIdValidator.find(parameters.front())) {
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
- return std::string();
+ return {};
}
if (compilerVersion.empty()) {
return parameters.front().empty() ? "1" : "0";
}
return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
- parameters.begin()->c_str(),
+ parameters.front().c_str(),
compilerVersion.c_str())
? "1"
: "0";
}
-};
-
-static const struct CCompilerVersionNode : public CompilerVersionNode
-{
- CCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<C_COMPILER_VERSION> may only be used with binary targets. It "
- "may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "C");
- }
-} cCompilerVersionNode;
-
-static const struct CxxCompilerVersionNode : public CompilerVersionNode
-{
- CxxCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<CXX_COMPILER_VERSION> may only be used with binary targets. It "
- "may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "CXX");
- }
-} cxxCompilerVersionNode;
-static const struct FortranCompilerVersionNode : public CompilerVersionNode
-{
- FortranCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
+ const char* const CompilerLanguage;
+};
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<Fortran_COMPILER_VERSION> may only be used with binary targets. "
- "It may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "Fortran");
- }
-} fortranCompilerVersionNode;
+static const CompilerVersionNode cCompilerVersionNode("C"),
+ cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
+ fortranCompilerVersionNode("Fortran");
struct PlatformIdNode : public cmGeneratorExpressionNode
{
PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -839,76 +794,19 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
return parameters.front().empty() ? "1" : "0";
}
- if (*parameters.begin() == platformId) {
- return "1";
+ for (auto& param : parameters) {
+ if (param == platformId) {
+ return "1";
+ }
}
return "0";
}
} platformIdNode;
-static const struct VersionGreaterNode : public cmGeneratorExpressionNode
-{
- VersionGreaterNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionGreaterNode;
-
-static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode
-{
- VersionGreaterEqNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionGreaterEqNode;
-
-static const struct VersionLessNode : public cmGeneratorExpressionNode
-{
- VersionLessNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionLessNode;
-
-static const struct VersionLessEqNode : public cmGeneratorExpressionNode
+template <cmSystemTools::CompareOp Op>
+struct VersionNode : public cmGeneratorExpressionNode
{
- VersionLessEqNode() {} // NOLINT(modernize-use-equals-default)
+ VersionNode() {} // NOLINT(modernize-use-equals-default)
int NumExpectedParameters() const override { return 2; }
@@ -918,33 +816,18 @@ static const struct VersionLessEqNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL,
- parameters.front().c_str(),
+ return cmSystemTools::VersionCompare(Op, parameters.front().c_str(),
parameters[1].c_str())
? "1"
: "0";
}
-} versionLessEqNode;
-
-static const struct VersionEqualNode : public cmGeneratorExpressionNode
-{
- VersionEqualNode() {} // NOLINT(modernize-use-equals-default)
+};
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionEqualNode;
+static const VersionNode<cmSystemTools::OP_GREATER> versionGreaterNode;
+static const VersionNode<cmSystemTools::OP_GREATER_EQUAL> versionGreaterEqNode;
+static const VersionNode<cmSystemTools::OP_LESS> versionLessNode;
+static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode;
+static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode;
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
{
@@ -1001,7 +884,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return configurationNode.Evaluate(parameters, context, content, nullptr);
}
static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
- if (!configValidator.find(*parameters.begin())) {
+ if (!configValidator.find(parameters.front())) {
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
return std::string();
@@ -1011,7 +894,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return parameters.front().empty() ? "1" : "0";
}
- if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+ if (cmsysString_strcasecmp(parameters.front().c_str(),
context->Config.c_str()) == 0) {
return "1";
}
@@ -1068,7 +951,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
{
CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -1099,10 +982,62 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
if (parameters.empty()) {
return context->Language;
}
- return context->Language == parameters.front() ? "1" : "0";
+
+ for (auto& param : parameters) {
+ if (context->Language == param) {
+ return "1";
+ }
+ }
+ return "0";
}
} languageNode;
+static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
+{
+ CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || context->Language.empty()) {
+ // reportError(context, content->GetOriginalExpression(), "");
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
+ "to specify include directories, compile definitions, and compile "
+ "options. It may not be used with the add_custom_command, "
+ "add_custom_target, or file(GENERATE) commands.");
+ return std::string();
+ }
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
+ return std::string();
+ }
+
+ const std::string& lang = context->Language;
+ if (lang == parameters.front()) {
+ std::vector<std::string> idParameter((parameters.cbegin() + 1),
+ parameters.cend());
+ return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
+ idParameter, context, content, dagChecker, lang);
+ }
+ return "0";
+ }
+} languageAndIdNode;
+
#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY
static const char* targetPropertyTransitiveWhitelist[] = {
@@ -1151,73 +1086,54 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
// This node handles errors on parameter count itself.
int NumExpectedParameters() const override { return OneOrMoreParameters; }
+ static const char* GetErrorText(std::string const& targetName,
+ std::string const& propertyName)
+ {
+ static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+ if (targetName.empty() && propertyName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name and property name.";
+ }
+ if (targetName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name.";
+ }
+ if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
+ if (!propertyNameValidator.find(propertyName)) {
+ return "Target name and property name not supported.";
+ }
+ return "Target name not supported.";
+ }
+ return nullptr;
+ }
+
std::string Evaluate(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
{
- if (parameters.size() != 1 && parameters.size() != 2) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:...> expression requires one or two parameters");
- return std::string();
- }
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
- cmGeneratorTarget const* target = context->HeadTarget;
- std::string propertyName = *parameters.begin();
-
- if (parameters.size() == 1) {
- context->HadHeadSensitiveCondition = true;
- }
- if (!target && parameters.size() == 1) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<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.");
- return std::string();
- }
+ cmGeneratorTarget const* target = nullptr;
+ std::string targetName, propertyName;
if (parameters.size() == 2) {
- if (parameters.begin()->empty() && parameters[1].empty()) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
- "target name and property name.");
- return std::string();
- }
- if (parameters.begin()->empty()) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
- "target name.");
- return std::string();
- }
-
- std::string targetName = parameters.front();
+ targetName = parameters[0];
propertyName = parameters[1];
- if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
- if (!propertyNameValidator.find(propertyName)) {
- ::reportError(context, content->GetOriginalExpression(),
- "Target name and property name not supported.");
- return std::string();
- }
- ::reportError(context, content->GetOriginalExpression(),
- "Target name not supported.");
+
+ if (const char* e = GetErrorText(targetName, propertyName)) {
+ reportError(context, content->GetOriginalExpression(), e);
return std::string();
}
- static const std::string propALIASED_TARGET = "ALIASED_TARGET";
- if (propertyName == propALIASED_TARGET) {
+ if (propertyName == "ALIASED_TARGET"_s) {
if (context->LG->GetMakefile()->IsAlias(targetName)) {
if (cmGeneratorTarget* tgt =
context->LG->FindGeneratorTargetToUse(targetName)) {
return tgt->GetName();
}
}
- return "";
+ return std::string();
}
target = context->LG->FindGeneratorTargetToUse(targetName);
@@ -1228,15 +1144,34 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return std::string();
}
context->AllTargets.insert(target);
- }
- if (target == context->HeadTarget) {
+ } else if (parameters.size() == 1) {
+ target = context->HeadTarget;
+ propertyName = parameters[0];
+
// Keep track of the properties seen while processing.
// The evaluation of the LINK_LIBRARIES generator expressions
// will check this to ensure that properties have one consistent
// value for all evaluations.
context->SeenTargetProperties.insert(propertyName);
+
+ context->HadHeadSensitiveCondition = true;
+ if (!target) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<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.");
+ return std::string();
+ }
+ } else {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires one or two parameters");
+ return std::string();
}
+
if (propertyName == "SOURCES") {
context->SourceSensitiveTargets.insert(target);
}
@@ -1292,7 +1227,12 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
break;
}
- const char* prop = target->GetProperty(propertyName);
+ std::string prop;
+ bool haveProp = false;
+ if (const char* p = target->GetProperty(propertyName)) {
+ prop = p;
+ haveProp = true;
+ }
if (dagCheckerParent) {
if (dagCheckerParent->EvaluatingGenexExpression() ||
@@ -1312,7 +1252,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
#undef TRANSITIVE_PROPERTY_COMPARE
- if (!prop) {
+ if (!haveProp) {
return std::string();
}
} else {
@@ -1368,7 +1308,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
}
- if (!prop) {
+ if (!haveProp) {
if (target->IsImported() ||
target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
return linkedTargetsContent;
@@ -1481,10 +1421,16 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
- if (gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ cmStateEnums::TargetType type = gt->GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::STATIC_LIBRARY &&
+ type != cmStateEnums::SHARED_LIBRARY &&
+ type != cmStateEnums::MODULE_LIBRARY &&
+ type != cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e;
e << "Objects of target \"" << tgtName
- << "\" referenced but is not an OBJECT library.";
+ << "\" referenced but is not an allowed library types (EXECUTABLE, "
+ << "STATIC, SHARED, MODULE, OBJECT).";
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
@@ -1950,39 +1896,37 @@ struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
static std::string Get(const std::string& result) { return result; }
};
-template <typename ArtifactT, typename ComponentT>
-struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
+struct TargetArtifactBase : public cmGeneratorExpressionNode
{
- TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 1; }
+ TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
- std::string Evaluate(
+protected:
+ cmGeneratorTarget* GetTarget(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
+ cmGeneratorExpressionDAGChecker* dagChecker) const
{
// Lookup the referenced target.
- std::string name = *parameters.begin();
+ std::string name = parameters.front();
if (!cmGeneratorExpression::IsValidTargetName(name)) {
::reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
- return std::string();
+ return nullptr;
}
cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
if (!target) {
::reportError(context, content->GetOriginalExpression(),
"No target \"" + name + "\"");
- return std::string();
+ return nullptr;
}
if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
::reportError(context, content->GetOriginalExpression(),
"Target \"" + name +
"\" is not an executable or library.");
- return std::string();
+ return nullptr;
}
if (dagChecker &&
(dagChecker->EvaluatingLinkLibraries(target) ||
@@ -1991,6 +1935,29 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
::reportError(context, content->GetOriginalExpression(),
"Expressions which require the linker language may not "
"be used while evaluating link libraries");
+ return nullptr;
+ }
+
+ return target;
+ }
+};
+
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifact : public TargetArtifactBase
+{
+ TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
return std::string();
}
context->DependTargets.insert(target);
@@ -2037,6 +2004,242 @@ static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
ArtifactPathTag>
targetBundleContentDirNode;
+//
+// To retrieve base name for various artifacts
+//
+template <typename ArtifactT>
+struct TargetOutputNameArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.so, .lib, .a).
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
+ "libraries and executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ return target->GetOutputName(context->Config, artifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
+ return std::string();
+ }
+
+ std::string language = target->GetLinkerLanguage(context->Config);
+
+ std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+
+ if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
+ return std::string();
+ }
+
+ cmStateEnums::TargetType targetType = target->GetType();
+
+ if (targetType != cmStateEnums::SHARED_LIBRARY &&
+ targetType != cmStateEnums::MODULE_LIBRARY &&
+ targetType != cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is allowed only for "
+ "targets with linker created artifacts.");
+ return std::string();
+ }
+
+ return target->GetPDBOutputName(context->Config) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileBaseNameArtifact : public TargetArtifactBase
+{
+ TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
+ target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileBaseNameArtifact<ArtifactNameTag>
+ targetFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactLinkerTag>
+ targetLinkerFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactPdbTag>
+ targetPdbFileBaseNameNode;
+
+class ArtifactFilePrefixTag;
+class ArtifactLinkerFilePrefixTag;
+class ArtifactFileSuffixTag;
+class ArtifactLinkerFileSuffixTag;
+
+template <typename ArtifactT>
+struct TargetFileArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFilePrefix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_PREFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFilePrefix(context->Config, artifact);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFileSuffix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_SUFFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFileSuffix(context->Config, artifact);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileArtifact : public TargetArtifactBase
+{
+ TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result =
+ TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
+ targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
+ targetLinkerFileSuffixNode;
+
static const struct ShellPathNode : public cmGeneratorExpressionNode
{
ShellPathNode() {} // NOLINT(modernize-use-equals-default)
@@ -2047,88 +2250,115 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- if (!cmSystemTools::FileIsFullPath(parameters.front())) {
+ std::vector<std::string> listIn;
+ cmSystemTools::ExpandListArgument(parameters.front(), listIn);
+ if (listIn.empty()) {
reportError(context, content->GetOriginalExpression(),
- "\"" + parameters.front() + "\" is not an absolute path.");
+ "\"\" is not an absolute path.");
return std::string();
}
- cmOutputConverter converter(context->LG->GetStateSnapshot());
- return converter.ConvertDirectorySeparatorsForShell(parameters.front());
+ cmStateSnapshot snapshot = context->LG->GetStateSnapshot();
+ cmOutputConverter converter(snapshot);
+ const char* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
+ std::vector<std::string> listOut;
+ listOut.reserve(listIn.size());
+ for (auto const& in : listIn) {
+ if (!cmSystemTools::FileIsFullPath(in)) {
+ reportError(context, content->GetOriginalExpression(),
+ "\"" + in + "\" is not an absolute path.");
+ return std::string();
+ }
+ listOut.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
+ }
+ return cmJoin(listOut, separator);
}
} shellPathNode;
const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
const std::string& identifier)
{
- typedef std::map<std::string, const cmGeneratorExpressionNode*> NodeMap;
- static NodeMap nodeMap;
- if (nodeMap.empty()) {
- nodeMap["0"] = &zeroNode;
- nodeMap["1"] = &oneNode;
- nodeMap["AND"] = &andNode;
- nodeMap["OR"] = &orNode;
- nodeMap["NOT"] = &notNode;
- nodeMap["C_COMPILER_ID"] = &cCompilerIdNode;
- nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode;
- nodeMap["Fortran_COMPILER_ID"] = &fortranCompilerIdNode;
- nodeMap["VERSION_GREATER"] = &versionGreaterNode;
- nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode;
- nodeMap["VERSION_LESS"] = &versionLessNode;
- nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode;
- nodeMap["VERSION_EQUAL"] = &versionEqualNode;
- nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
- nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
- nodeMap["Fortran_COMPILER_VERSION"] = &fortranCompilerVersionNode;
- nodeMap["PLATFORM_ID"] = &platformIdNode;
- nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode;
- nodeMap["CONFIGURATION"] = &configurationNode;
- nodeMap["CONFIG"] = &configurationTestNode;
- nodeMap["TARGET_FILE"] = &targetNodeGroup.File;
- nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File;
- nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File;
- nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File;
- nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName;
- nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName;
- nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName;
- nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName;
- nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir;
- nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir;
- nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir;
- nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir;
- nodeMap["TARGET_BUNDLE_DIR"] = &targetBundleDirNode;
- nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode;
- nodeMap["STREQUAL"] = &strEqualNode;
- nodeMap["EQUAL"] = &equalNode;
- nodeMap["IN_LIST"] = &inListNode;
- nodeMap["LOWER_CASE"] = &lowerCaseNode;
- nodeMap["UPPER_CASE"] = &upperCaseNode;
- nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
- nodeMap["BOOL"] = &boolNode;
- nodeMap["IF"] = &ifNode;
- nodeMap["ANGLE-R"] = &angle_rNode;
- nodeMap["COMMA"] = &commaNode;
- nodeMap["SEMICOLON"] = &semicolonNode;
- nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
- nodeMap["TARGET_NAME"] = &targetNameNode;
- nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
- nodeMap["TARGET_POLICY"] = &targetPolicyNode;
- nodeMap["TARGET_EXISTS"] = &targetExistsNode;
- nodeMap["TARGET_NAME_IF_EXISTS"] = &targetNameIfExistsNode;
- nodeMap["TARGET_GENEX_EVAL"] = &targetGenexEvalNode;
- nodeMap["GENEX_EVAL"] = &genexEvalNode;
- nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
- nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
- nodeMap["INSTALL_PREFIX"] = &installPrefixNode;
- nodeMap["JOIN"] = &joinNode;
- nodeMap["LINK_ONLY"] = &linkOnlyNode;
- nodeMap["COMPILE_LANGUAGE"] = &languageNode;
- nodeMap["SHELL_PATH"] = &shellPathNode;
- }
- NodeMap::const_iterator i = nodeMap.find(identifier);
- if (i == nodeMap.end()) {
- return nullptr;
+ static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
+ { "0", &zeroNode },
+ { "1", &oneNode },
+ { "AND", &andNode },
+ { "OR", &orNode },
+ { "NOT", &notNode },
+ { "C_COMPILER_ID", &cCompilerIdNode },
+ { "CXX_COMPILER_ID", &cxxCompilerIdNode },
+ { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
+ { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
+ { "VERSION_GREATER", &versionGreaterNode },
+ { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
+ { "VERSION_LESS", &versionLessNode },
+ { "VERSION_LESS_EQUAL", &versionLessEqNode },
+ { "VERSION_EQUAL", &versionEqualNode },
+ { "C_COMPILER_VERSION", &cCompilerVersionNode },
+ { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
+ { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
+ { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
+ { "PLATFORM_ID", &platformIdNode },
+ { "COMPILE_FEATURES", &compileFeaturesNode },
+ { "CONFIGURATION", &configurationNode },
+ { "CONFIG", &configurationTestNode },
+ { "TARGET_FILE", &targetNodeGroup.File },
+ { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
+ { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
+ { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
+ { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
+ { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
+ { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
+ { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+ { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+ { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+ { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
+ { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
+ { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
+ { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
+ { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
+ { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
+ { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
+ { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
+ { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
+ { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
+ { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
+ { "STREQUAL", &strEqualNode },
+ { "EQUAL", &equalNode },
+ { "IN_LIST", &inListNode },
+ { "FILTER", &filterNode },
+ { "REMOVE_DUPLICATES", &removeDuplicatesNode },
+ { "LOWER_CASE", &lowerCaseNode },
+ { "UPPER_CASE", &upperCaseNode },
+ { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
+ { "BOOL", &boolNode },
+ { "IF", &ifNode },
+ { "ANGLE-R", &angle_rNode },
+ { "COMMA", &commaNode },
+ { "SEMICOLON", &semicolonNode },
+ { "TARGET_PROPERTY", &targetPropertyNode },
+ { "TARGET_NAME", &targetNameNode },
+ { "TARGET_OBJECTS", &targetObjectsNode },
+ { "TARGET_POLICY", &targetPolicyNode },
+ { "TARGET_EXISTS", &targetExistsNode },
+ { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
+ { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+ { "GENEX_EVAL", &genexEvalNode },
+ { "BUILD_INTERFACE", &buildInterfaceNode },
+ { "INSTALL_INTERFACE", &installInterfaceNode },
+ { "INSTALL_PREFIX", &installPrefixNode },
+ { "JOIN", &joinNode },
+ { "LINK_ONLY", &linkOnlyNode },
+ { "COMPILE_LANG_AND_ID", &languageAndIdNode },
+ { "COMPILE_LANGUAGE", &languageNode },
+ { "SHELL_PATH", &shellPathNode }
+ };
+
+ {
+ auto itr = nodeMap.find(identifier);
+ if (itr != nodeMap.end()) {
+ return itr->second;
+ }
}
- return i->second;
+ return nullptr;
}
void reportError(cmGeneratorExpressionContext* context,
diff --git a/Source/cmGeneratorExpressionNode.h b/Source/cmGeneratorExpressionNode.h
index 3dbfc6e5e..7a369249f 100644
--- a/Source/cmGeneratorExpressionNode.h
+++ b/Source/cmGeneratorExpressionNode.h
@@ -20,7 +20,9 @@ struct cmGeneratorExpressionNode
{
DynamicParameters = 0,
OneOrMoreParameters = -1,
- OneOrZeroParameters = -2
+ TwoOrMoreParameters = -2,
+ ZeroOrMoreParameters = -3,
+ OneOrZeroParameters = -4
};
virtual ~cmGeneratorExpressionNode() = default;
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
index 949a86d81..304378dfe 100644
--- a/Source/cmGeneratorExpressionParser.cxx
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGeneratorExpressionParser.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpressionEvaluator.h"
#include <assert.h>
@@ -47,14 +48,14 @@ static void extendResult(
if (!result.empty() &&
(*(result.end() - 1))->GetType() ==
cmGeneratorExpressionEvaluator::Text &&
- (*contents.begin())->GetType() == cmGeneratorExpressionEvaluator::Text) {
+ contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
textContent->Extend(
- static_cast<TextContent*>(*contents.begin())->GetLength());
- delete *contents.begin();
- result.insert(result.end(), contents.begin() + 1, contents.end());
+ static_cast<TextContent*>(contents.front())->GetLength());
+ delete contents.front();
+ cmAppend(result, contents.begin() + 1, contents.end());
} else {
- result.insert(result.end(), contents.begin(), contents.end());
+ cmAppend(result, contents);
}
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 25349d42e..036a07d1c 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -28,6 +28,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
@@ -64,20 +65,137 @@ const char* cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
class cmGeneratorTarget::TargetPropertyEntry
{
+protected:
static cmLinkImplItem NoLinkImplItem;
public:
- TargetPropertyEntry(std::unique_ptr<cmCompiledGeneratorExpression> cge,
- cmLinkImplItem const& item = NoLinkImplItem)
- : ge(std::move(cge))
- , LinkImplItem(item)
+ TargetPropertyEntry(cmLinkImplItem const& item)
+ : LinkImplItem(item)
{
}
- const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+ virtual ~TargetPropertyEntry() = default;
+
+ virtual const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ std::string const& language = std::string()) const = 0;
+ virtual const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language = std::string()) const = 0;
+
+ virtual cmListFileBacktrace GetBacktrace() const = 0;
+ virtual std::string const& GetInput() const = 0;
+ virtual bool GetHadContextSensitiveCondition() const { return false; }
+
cmLinkImplItem const& LinkImplItem;
+
+private:
+ cmListFileBacktrace Backtrace;
};
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
+class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , ge(std::move(cge))
+ {
+ }
+
+ const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ std::string const& language = std::string()) const override
+ {
+ return this->ge->Evaluate(lg, config, quiet, headTarget, currentTarget,
+ dagChecker, language);
+ }
+ const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language = std::string()) const override
+ {
+ return this->ge->Evaluate(lg, config, quiet, headTarget, dagChecker,
+ language);
+ }
+
+ cmListFileBacktrace GetBacktrace() const override
+ {
+ return this->ge->GetBacktrace();
+ }
+
+ std::string const& GetInput() const override { return this->ge->GetInput(); }
+
+ bool GetHadContextSensitiveCondition() const override
+ {
+ return this->ge->GetHadContextSensitiveCondition();
+ }
+
+private:
+ const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+};
+
+class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryString(std::string propertyValue,
+ cmListFileBacktrace backtrace,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , PropertyValue(std::move(propertyValue))
+ , Backtrace(std::move(backtrace))
+ {
+ }
+
+ const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+ cmGeneratorTarget const*,
+ cmGeneratorTarget const*,
+ cmGeneratorExpressionDAGChecker*,
+ std::string const&) const override
+ {
+ return this->PropertyValue;
+ }
+ const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+ cmGeneratorTarget const*,
+ cmGeneratorExpressionDAGChecker*,
+ std::string const&) const override
+ {
+ return this->PropertyValue;
+ }
+
+ cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
+ std::string const& GetInput() const override { return this->PropertyValue; }
+
+private:
+ std::string PropertyValue;
+ cmListFileBacktrace Backtrace;
+};
+
+cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry(
+ const std::string& propertyValue,
+ cmListFileBacktrace backtrace = cmListFileBacktrace(),
+ bool evaluateForBuildsystem = false)
+{
+ if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
+ cmGeneratorExpression ge(std::move(backtrace));
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(propertyValue);
+ cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
+ return new TargetPropertyEntryGenex(std::move(cge));
+ }
+
+ return new TargetPropertyEntryString(propertyValue, backtrace);
+}
+
void CreatePropertyGeneratorExpressions(
cmStringRange entries, cmBacktraceRange backtraces,
std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
@@ -86,11 +204,8 @@ void CreatePropertyGeneratorExpressions(
std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
for (std::vector<std::string>::const_iterator it = entries.begin();
it != entries.end(); ++it, ++btIt) {
- cmGeneratorExpression ge(*btIt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
- cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
items.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
}
}
@@ -147,7 +262,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
this->DLLPlatform =
!this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
- this->PolicyMap = t->PolicyMap;
+ this->PolicyMap = t->GetPolicyMap();
}
cmGeneratorTarget::~cmGeneratorTarget()
@@ -166,7 +281,7 @@ const char* cmGeneratorTarget::GetSourcesProperty() const
{
std::vector<std::string> values;
for (TargetPropertyEntry* se : this->SourceEntries) {
- values.push_back(se->ge->GetInput());
+ values.push_back(se->GetInput());
}
static std::string value;
value.clear();
@@ -349,6 +464,150 @@ std::string cmGeneratorTarget::GetOutputName(
return i->second;
}
+std::string cmGeneratorTarget::GetFilePrefix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ const char* prefix = this->GetFilePrefixInternal(artifact);
+
+ return prefix ? prefix : std::string();
+ }
+
+ std::string prefix, suffix, base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return prefix;
+}
+std::string cmGeneratorTarget::GetFileSuffix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ const char* suffix = this->GetFileSuffixInternal(artifact);
+
+ return suffix ? suffix : std::string();
+ }
+
+ std::string prefix, suffix, base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return suffix;
+}
+
+std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
+{
+ const char* postfix = nullptr;
+ if (!config.empty()) {
+ std::string configProp = cmSystemTools::UpperCase(config);
+ configProp += "_POSTFIX";
+ postfix = this->GetProperty(configProp);
+ // Mac application bundles and frameworks have no postfix.
+ if (!this->IsImported() && postfix &&
+ (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
+ postfix = nullptr;
+ }
+ }
+ return postfix ? postfix : std::string();
+}
+
+const char* cmGeneratorTarget::GetFilePrefixInternal(
+ cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+ // no prefix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty prefix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute prefix value.
+ const char* targetPrefix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
+ : this->GetProperty("PREFIX"));
+
+ if (!targetPrefix) {
+ const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
+ if (!language.empty() && prefixVar && *prefixVar) {
+ std::string langPrefix = prefixVar + std::string("_") + language;
+ targetPrefix = this->Makefile->GetDefinition(langPrefix);
+ }
+
+ // if there is no prefix on the target nor specific language
+ // use the cmake definition.
+ if (!targetPrefix && prefixVar) {
+ targetPrefix = this->Makefile->GetDefinition(prefixVar);
+ }
+ }
+
+ return targetPrefix;
+}
+const char* cmGeneratorTarget::GetFileSuffixInternal(
+ cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+ // no suffix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty suffix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute suffix value.
+ const char* targetSuffix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
+ : this->GetProperty("SUFFIX"));
+
+ if (!targetSuffix) {
+ const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
+ if (!language.empty() && suffixVar && *suffixVar) {
+ std::string langSuffix = suffixVar + std::string("_") + language;
+ targetSuffix = this->Makefile->GetDefinition(langSuffix);
+ }
+
+ // if there is no suffix on the target nor specific language
+ // use the cmake definition.
+ if (!targetSuffix && suffixVar) {
+ targetSuffix = this->Makefile->GetDefinition(suffixVar);
+ }
+ }
+
+ return targetSuffix;
+}
+
void cmGeneratorTarget::ClearSourcesCache()
{
this->KindedSourcesMap.clear();
@@ -358,13 +617,9 @@ void cmGeneratorTarget::ClearSourcesCache()
void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
{
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
- cge->SetEvaluateForBuildsystem(true);
- this->SourceEntries.insert(before ? this->SourceEntries.begin()
- : this->SourceEntries.end(),
- new TargetPropertyEntry(std::move(cge)));
+ this->SourceEntries.insert(
+ before ? this->SourceEntries.begin() : this->SourceEntries.end(),
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
this->ClearSourcesCache();
}
@@ -386,14 +641,10 @@ void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
bool before)
{
this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
- cge->SetEvaluateForBuildsystem(true);
this->IncludeDirectoriesEntries.insert(
before ? this->IncludeDirectoriesEntries.begin()
: this->IncludeDirectoriesEntries.end(),
- new TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
}
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
@@ -853,8 +1104,7 @@ static void AddInterfaceEntries(
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+ entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
}
}
}
@@ -876,8 +1126,7 @@ static void AddObjectEntries(
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+ entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
}
}
}
@@ -899,12 +1148,12 @@ static bool processSources(
cmLinkImplItem const& item = entry->LinkImplItem;
std::string const& targetName = item.AsStr();
std::vector<std::string> entrySources;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
- dagChecker),
- entrySources);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt, tgt,
+ dagChecker),
+ entrySources);
- if (entry->ge->GetHadContextSensitiveCondition()) {
+ if (entry->GetHadContextSensitiveCondition()) {
contextDependent = true;
}
@@ -939,7 +1188,7 @@ static bool processSources(
std::string usedSources;
for (std::string const& src : entrySources) {
if (uniqueSrcs.insert(src).second) {
- srcs.emplace_back(src, entry->ge->GetBacktrace());
+ srcs.emplace_back(src, entry->GetBacktrace());
if (debugSources) {
usedSources += " * " + src + "\n";
}
@@ -950,7 +1199,7 @@ static bool processSources(
MessageType::LOG,
std::string("Used sources for target ") + tgt->GetName() + ":\n" +
usedSources,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
return contextDependent;
@@ -1606,13 +1855,7 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const
return "";
}
// Compute the soname that will be built.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
- return soName;
+ return this->GetLibraryNames(config).SharedObject;
}
static bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
@@ -2378,7 +2621,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
std::set<cmGeneratorTarget*> targets;
for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) {
- std::string const& command = *cCmdLine.begin();
+ std::string const& command = cCmdLine.front();
// Check for a target with this name.
if (cmGeneratorTarget* t =
this->LocalGenerator->FindGeneratorTargetToUse(command)) {
@@ -2534,10 +2777,10 @@ static void processIncludeDirectories(
bool const fromImported = item.Target && item.Target->IsImported();
bool const checkCMP0027 = item.FromGenex;
std::vector<std::string> entryIncludes;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryIncludes);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryIncludes);
std::string usedIncludes;
for (std::string& entryInclude : entryIncludes) {
@@ -2615,7 +2858,7 @@ static void processIncludeDirectories(
std::string inc = entryInclude;
if (uniqueIncludes.insert(inc).second) {
- includes.emplace_back(inc, entry->ge->GetBacktrace());
+ includes.emplace_back(inc, entry->GetBacktrace());
if (debugIncludes) {
usedIncludes += " * " + inc + "\n";
}
@@ -2626,7 +2869,7 @@ static void processIncludeDirectories(
MessageType::LOG,
std::string("Used includes for target ") + tgt->GetName() + ":\n" +
usedIncludes,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -2678,11 +2921,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
libDir = frameworkCheck.match(1);
- cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(libDir.c_str());
linkInterfaceIncludeDirectoriesEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(libDir));
}
}
@@ -2712,10 +2952,10 @@ static void processOptionsInternal(
{
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
std::vector<std::string> entryOptions;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryOptions);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryOptions);
std::string usedOptions;
for (std::string const& opt : entryOptions) {
if (uniqueOptions.insert(opt).second) {
@@ -2724,10 +2964,10 @@ static void processOptionsInternal(
std::vector<std::string> tmp;
cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
for (std::string& o : tmp) {
- options.emplace_back(std::move(o), entry->ge->GetBacktrace());
+ options.emplace_back(std::move(o), entry->GetBacktrace());
}
} else {
- options.emplace_back(opt, entry->ge->GetBacktrace());
+ options.emplace_back(opt, entry->GetBacktrace());
}
if (debugOptions) {
usedOptions += " * " + opt + "\n";
@@ -2739,7 +2979,7 @@ static void processOptionsInternal(
MessageType::LOG,
std::string("Used ") + logName + std::string(" for target ") +
tgt->GetName() + ":\n" + usedOptions,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -2943,11 +3183,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
CM_FALLTHROUGH;
}
case cmPolicies::OLD: {
- cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(configProp);
linkInterfaceCompileDefinitionsEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(configProp));
} break;
case cmPolicies::NEW:
case cmPolicies::REQUIRED_ALWAYS:
@@ -3173,12 +3410,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
std::vector<std::string> options;
- cmGeneratorExpression ge;
cmSystemTools::ExpandListArgument(linkOptions, options);
for (const auto& option : options) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(option);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ entries.push_back(CreateTargetPropertyEntry(option));
}
}
processStaticLibraryLinkOptions(this, entries, result, uniqueOptions,
@@ -3202,10 +3436,10 @@ void processLinkDirectories(
std::string const& targetName = item.AsStr();
std::vector<std::string> entryDirectories;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryDirectories);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryDirectories);
std::string usedDirectories;
for (std::string& entryDirectory : entryDirectories) {
@@ -3261,7 +3495,7 @@ void processLinkDirectories(
MessageType::LOG,
std::string("Used link directories for target ") + tgt->GetName() +
":\n" + usedDirectories,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -3358,12 +3592,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) {
std::vector<std::string> depends;
- cmGeneratorExpression ge;
cmSystemTools::ExpandListArgument(linkDepends, depends);
for (const auto& depend : depends) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depend);
- linkDependsEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ linkDependsEntries.push_back(CreateTargetPropertyEntry(depend));
}
}
AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS",
@@ -3383,17 +3614,13 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
// Get the names.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
+ cmGeneratorTarget::Names targetNames;
if (this->GetType() == cmStateEnums::EXECUTABLE) {
- this->GetExecutableNames(name, realName, impName, pdbName, config);
+ targetNames = this->GetExecutableNames(config);
} else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::MODULE_LIBRARY) {
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+ targetNames = this->GetLibraryNames(config);
} else {
return;
}
@@ -3404,34 +3631,34 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
// Add each name.
std::string f;
- if (!name.empty()) {
+ if (!targetNames.Output.empty()) {
f = dir;
f += "/";
- f += name;
+ f += targetNames.Output;
gg->AddToManifest(f);
}
- if (!soName.empty()) {
+ if (!targetNames.SharedObject.empty()) {
f = dir;
f += "/";
- f += soName;
+ f += targetNames.SharedObject;
gg->AddToManifest(f);
}
- if (!realName.empty()) {
+ if (!targetNames.Real.empty()) {
f = dir;
f += "/";
- f += realName;
+ f += targetNames.Real;
gg->AddToManifest(f);
}
- if (!pdbName.empty()) {
+ if (!targetNames.PDB.empty()) {
f = dir;
f += "/";
- f += pdbName;
+ f += targetNames.PDB;
gg->AddToManifest(f);
}
- if (!impName.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
f = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
f += "/";
- f += impName;
+ f += targetNames.ImportLibrary;
gg->AddToManifest(f);
}
}
@@ -3509,29 +3736,17 @@ std::string cmGeneratorTarget::NormalGetRealName(
if (this->GetType() == cmStateEnums::EXECUTABLE) {
// Compute the real name that will be built.
- std::string name;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetExecutableNames(name, realName, impName, pdbName, config);
- return realName;
+ return this->GetExecutableNames(config).Real;
}
// Compute the real name that will be built.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
- return realName;
-}
-
-void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
+ return this->GetLibraryNames(config).Real;
+}
+
+cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
+ const std::string& config) const
{
+ cmGeneratorTarget::Names targetNames;
+
// This should not be called for imported targets.
// TODO: Split cmTarget into a class hierarchy to get compile-time
// enforcement of the limited imported target API.
@@ -3539,7 +3754,6 @@ void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
std::string msg = "GetLibraryNames called on imported target: ";
msg += this->GetName();
this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
- return;
}
// Check for library version properties.
@@ -3565,50 +3779,51 @@ void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
// Get the components of the library name.
std::string prefix;
- std::string base;
std::string suffix;
this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, base, suffix);
+ prefix, targetNames.Base, suffix);
// The library name.
- name = prefix + base + suffix;
+ targetNames.Output = prefix + targetNames.Base + suffix;
if (this->IsFrameworkOnApple()) {
- realName = prefix;
+ targetNames.Real = prefix;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
- realName += "Versions/";
- realName += this->GetFrameworkVersion();
- realName += "/";
+ targetNames.Real += "Versions/";
+ targetNames.Real += this->GetFrameworkVersion();
+ targetNames.Real += "/";
}
- realName += base;
- soName = realName;
+ targetNames.Real += targetNames.Base;
+ targetNames.SharedObject = targetNames.Real;
} else {
// The library's soname.
- this->ComputeVersionedName(soName, prefix, base, suffix, name, soversion);
+ this->ComputeVersionedName(targetNames.SharedObject, prefix,
+ targetNames.Base, suffix, targetNames.Output,
+ soversion);
// The library's real name on disk.
- this->ComputeVersionedName(realName, prefix, base, suffix, name, version);
+ this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
+ suffix, targetNames.Output, version);
}
// The import library name.
if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::MODULE_LIBRARY) {
- impName =
+ targetNames.ImportLibrary =
this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
- } else {
- impName.clear();
}
// The program database file name.
- pdbName = this->GetPDBName(config);
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
}
-void cmGeneratorTarget::GetExecutableNames(std::string& name,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
+cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
+ const std::string& config) const
{
+ cmGeneratorTarget::Names targetNames;
+
// This should not be called for imported targets.
// TODO: Split cmTarget into a class hierarchy to get compile-time
// enforcement of the limited imported target API.
@@ -3633,34 +3848,35 @@ void cmGeneratorTarget::GetExecutableNames(std::string& name,
// Get the components of the executable name.
std::string prefix;
- std::string base;
std::string suffix;
this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, base, suffix);
+ prefix, targetNames.Base, suffix);
// The executable name.
- name = prefix + base + suffix;
+ targetNames.Output = prefix + targetNames.Base + suffix;
// The executable's real name on disk.
#if defined(__CYGWIN__)
- realName = prefix + base;
+ targetNames.Real = prefix + targetNames.Base;
#else
- realName = name;
+ targetNames.Real = targetNames.Output;
#endif
if (version) {
- realName += "-";
- realName += version;
+ targetNames.Real += "-";
+ targetNames.Real += version;
}
#if defined(__CYGWIN__)
- realName += suffix;
+ targetNames.Real += suffix;
#endif
// The import library name.
- impName =
+ targetNames.ImportLibrary =
this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
// The program database file name.
- pdbName = this->GetPDBName(config);
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
}
std::string cmGeneratorTarget::GetFullNameInternal(
@@ -3716,6 +3932,11 @@ void cmGeneratorTarget::GetFullNameInternal(
return;
}
+ // retrieve prefix and suffix
+ std::string ll = this->GetLinkerLanguage(config);
+ const char* targetPrefix = this->GetFilePrefixInternal(artifact, ll);
+ const char* targetSuffix = this->GetFileSuffixInternal(artifact, ll);
+
// The implib option is only allowed for shared libraries, module
// libraries, and executables.
if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
@@ -3725,47 +3946,7 @@ void cmGeneratorTarget::GetFullNameInternal(
}
// Compute the full name for main target types.
- const char* targetPrefix =
- (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
- : this->GetProperty("PREFIX"));
- const char* targetSuffix =
- (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
- : this->GetProperty("SUFFIX"));
- const char* configPostfix = nullptr;
- if (!config.empty()) {
- std::string configProp = cmSystemTools::UpperCase(config);
- configProp += "_POSTFIX";
- configPostfix = this->GetProperty(configProp);
- // Mac application bundles and frameworks have no postfix.
- if (configPostfix &&
- (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
- configPostfix = nullptr;
- }
- }
- const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
- const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
-
- // Check for language-specific default prefix and suffix.
- std::string ll = this->GetLinkerLanguage(config);
- if (!ll.empty()) {
- if (!targetSuffix && suffixVar && *suffixVar) {
- std::string langSuff = suffixVar + std::string("_") + ll;
- targetSuffix = this->Makefile->GetDefinition(langSuff);
- }
- if (!targetPrefix && prefixVar && *prefixVar) {
- std::string langPrefix = prefixVar + std::string("_") + ll;
- targetPrefix = this->Makefile->GetDefinition(langPrefix);
- }
- }
-
- // if there is no prefix on the target use the cmake definition
- if (!targetPrefix && prefixVar) {
- targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str();
- }
- // if there is no suffix on the target use the cmake definition
- if (!targetSuffix && suffixVar) {
- targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str();
- }
+ const std::string configPostfix = this->GetFilePostfix(config);
// frameworks have directory prefix but no suffix
std::string fw_prefix;
@@ -3790,7 +3971,7 @@ void cmGeneratorTarget::GetFullNameInternal(
outBase += this->GetOutputName(config, artifact);
// Append the per-configuration postfix.
- outBase += configPostfix ? configPostfix : "";
+ outBase += configPostfix;
// Name shared libraries with their version number on some platforms.
if (const char* soversion = this->GetProperty("SOVERSION")) {
@@ -3812,6 +3993,31 @@ std::string cmGeneratorTarget::GetLinkerLanguage(
return this->GetLinkClosure(config)->LinkerLanguage;
}
+std::string cmGeneratorTarget::GetPDBOutputName(
+ const std::string& config) const
+{
+ std::string base =
+ this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
+
+ std::vector<std::string> props;
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!configUpper.empty()) {
+ // PDB_NAME_<CONFIG>
+ props.push_back("PDB_NAME_" + configUpper);
+ }
+
+ // PDB_NAME
+ props.emplace_back("PDB_NAME");
+
+ for (std::string const& p : props) {
+ if (const char* outName = this->GetProperty(p)) {
+ base = outName;
+ break;
+ }
+ }
+ return base;
+}
+
std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
{
std::string prefix;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 59d38afd7..0e0ee6a6f 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -69,9 +69,9 @@ public:
std::string GetExportName() const;
std::vector<std::string> GetPropertyKeys() const;
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
void GetSourceFiles(std::vector<cmSourceFile*>& files,
@@ -503,6 +503,9 @@ public:
OutputInfo const* GetOutputInfo(const std::string& config) const;
+ // Get the target PDB base name.
+ std::string GetPDBOutputName(const std::string& config) const;
+
/** Get the name of the pdb file for the target. */
std::string GetPDBName(const std::string& config = "") const;
@@ -531,6 +534,18 @@ public:
std::string GetOutputName(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
+ /** Get target file prefix */
+ std::string GetFilePrefix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+ /** Get target file prefix */
+ std::string GetFileSuffix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** Get target file postfix */
+ std::string GetFilePostfix(const std::string& config) const;
+
/** Clears cached meta data for local and external source files.
* The meta data will be recomputed on demand.
*/
@@ -568,19 +583,25 @@ public:
void GetAutoUicOptions(std::vector<std::string>& result,
const std::string& config) const;
+ struct Names
+ {
+ std::string Base;
+ std::string Output;
+ std::string Real;
+ std::string ImportLibrary;
+ std::string PDB;
+ std::string SharedObject;
+ };
+
/** Get the names of the executable needed to generate a build rule
that takes into account executable version numbers. This should
be called only on an executable target. */
- void GetExecutableNames(std::string& name, std::string& realName,
- std::string& impName, std::string& pdbName,
- const std::string& config) const;
+ Names GetExecutableNames(const std::string& config) const;
/** Get the names of the library needed to generate a build rule
that takes into account shared library version numbers. This
should be called only on a library target. */
- void GetLibraryNames(std::string& name, std::string& soName,
- std::string& realName, std::string& impName,
- std::string& pdbName, const std::string& config) const;
+ Names GetLibraryNames(const std::string& config) const;
/**
* Compute whether this target must be relinked before installing.
@@ -596,7 +617,7 @@ public:
pdb output directory is given. */
std::string GetPDBDirectory(const std::string& config) const;
- ///! Return the preferred linker language for this target
+ //! Return the preferred linker language for this target
std::string GetLinkerLanguage(const std::string& config) const;
/** Does this target have a GNU implib to convert to MS format? */
@@ -719,6 +740,11 @@ private:
mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
+ const char* GetFilePrefixInternal(cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
+ const char* GetFileSuffixInternal(cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
+
std::string GetFullNameInternal(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
void GetFullNameInternal(const std::string& config,
diff --git a/Source/cmGetPipes.cxx b/Source/cmGetPipes.cxx
new file mode 100644
index 000000000..ad323f7ee
--- /dev/null
+++ b/Source/cmGetPipes.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetPipes.h"
+
+#include "cm_uv.h"
+
+#include <fcntl.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+
+int cmGetPipes(int* fds)
+{
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = nullptr;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return uv_translate_sys_error(GetLastError());
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return uv_translate_sys_error(GetLastError());
+ }
+ return 0;
+}
+#else
+# include <errno.h>
+# include <unistd.h>
+
+int cmGetPipes(int* fds)
+{
+ if (pipe(fds) == -1) {
+ return uv_translate_sys_error(errno);
+ }
+
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return uv_translate_sys_error(errno);
+ }
+ return 0;
+}
+#endif
diff --git a/Source/cmGetPipes.h b/Source/cmGetPipes.h
new file mode 100644
index 000000000..2a46b51b3
--- /dev/null
+++ b/Source/cmGetPipes.h
@@ -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. */
+#ifndef cmGetPipes_h
+#define cmGetPipes_h
+
+int cmGetPipes(int* fds);
+
+#endif
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
index c1f0742f2..da27971de 100644
--- a/Source/cmGhsMultiGpj.cxx
+++ b/Source/cmGhsMultiGpj.cxx
@@ -2,16 +2,17 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGhsMultiGpj.h"
-#include "cmGeneratedFileStream.h"
+#include <ostream>
static const char* GHS_TAG[] = { "[INTEGRITY Application]",
"[Library]",
"[Project]",
"[Program]",
"[Reference]",
- "[Subproject]" };
+ "[Subproject]",
+ "[Custom Target]" };
-const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
+const char* GhsMultiGpj::GetGpjTag(Types gpjType)
{
char const* tag;
switch (gpjType) {
@@ -21,6 +22,7 @@ const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
case PROGRAM:
case REFERENCE:
case SUBPROJECT:
+ case CUSTOM_TARGET:
tag = GHS_TAG[gpjType];
break;
default:
@@ -29,7 +31,7 @@ const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
return tag;
}
-void GhsMultiGpj::WriteGpjTag(Types const gpjType, std::ostream& fout)
+void GhsMultiGpj::WriteGpjTag(Types gpjType, std::ostream& fout)
{
char const* tag;
tag = GhsMultiGpj::GetGpjTag(gpjType);
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
index 6d59225da..e588150f4 100644
--- a/Source/cmGhsMultiGpj.h
+++ b/Source/cmGhsMultiGpj.h
@@ -6,8 +6,6 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
-class cmGeneratedFileStream;
-
class GhsMultiGpj
{
public:
@@ -18,12 +16,13 @@ public:
PROJECT,
PROGRAM,
REFERENCE,
- SUBPROJECT
+ SUBPROJECT,
+ CUSTOM_TARGET
};
- static void WriteGpjTag(Types const gpjType, std::ostream& fout);
+ static void WriteGpjTag(Types gpjType, std::ostream& fout);
- static const char* GetGpjTag(Types const gpjType);
+ static const char* GetGpjTag(Types gpjType);
};
#endif // ! cmGhsMultiGpjType_h
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 5fe350c10..b80da7231 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -2,23 +2,41 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGhsMultiTargetGenerator.h"
-#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGhsMultiGenerator.h"
#include "cmLinkLineComputer.h"
+#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
+#include "cmOutputConverter.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
#include "cmSourceGroup.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
+#include <algorithm>
+#include <ostream>
+#include <set>
+#include <utility>
+
cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
: GeneratorTarget(target)
, LocalGenerator(
static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
, Makefile(target->Target->GetMakefile())
, Name(target->GetName())
+#ifdef _WIN32
+ , CmdWindowsShell(true)
+#else
+ , CmdWindowsShell(false)
+#endif
{
// Store the configuration name that is being used
if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
@@ -30,9 +48,7 @@ cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
}
}
-cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
-{
-}
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
void cmGhsMultiTargetGenerator::Generate()
{
@@ -40,12 +56,8 @@ void cmGhsMultiTargetGenerator::Generate()
switch (this->GeneratorTarget->GetType()) {
case cmStateEnums::EXECUTABLE: {
// Get the name of the executable to generate.
- std::string targetName;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetExecutableNames(
- targetName, this->TargetNameReal, targetNameImport, targetNamePDB,
- this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
} else {
@@ -54,13 +66,8 @@ void cmGhsMultiTargetGenerator::Generate()
break;
}
case cmStateEnums::STATIC_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(
- targetName, targetNameSO, this->TargetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
this->TagType = GhsMultiGpj::LIBRARY;
break;
}
@@ -71,13 +78,8 @@ void cmGhsMultiTargetGenerator::Generate()
return;
}
case cmStateEnums::OBJECT_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(
- targetName, targetNameSO, this->TargetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
this->TagType = GhsMultiGpj::SUBPROJECT;
break;
}
@@ -88,10 +90,19 @@ void cmGhsMultiTargetGenerator::Generate()
return;
}
case cmStateEnums::UTILITY: {
- std::string msg = "add_custom_target(<name> ...) not supported: ";
- msg += this->Name;
- cmSystemTools::Message(msg);
- return;
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ break;
+ }
+ case cmStateEnums::GLOBAL_TARGET: {
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ if (this->TargetNameReal ==
+ this->GetGlobalGenerator()->GetInstallTargetName()) {
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ } else {
+ return;
+ }
+ break;
}
default:
return;
@@ -108,29 +119,29 @@ void cmGhsMultiTargetGenerator::Generate()
void cmGhsMultiTargetGenerator::GenerateTarget()
{
- // Open the filestream in copy-if-different mode.
- std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
- fname += "/";
- fname += this->Name;
- fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
- cmGeneratedFileStream fout(fname.c_str());
+ // Open the target file in copy-if-different mode.
+ std::string fproj = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fproj += "/";
+ fproj += this->Name;
+ fproj += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+ cmGeneratedFileStream fout(fproj);
fout.SetCopyIfDifferent(true);
this->GetGlobalGenerator()->WriteFileHeader(fout);
GhsMultiGpj::WriteGpjTag(this->TagType, fout);
- const std::string language(
- this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
-
- this->WriteTargetSpecifics(fout, this->ConfigName);
- this->SetCompilerFlags(this->ConfigName, language);
- this->WriteCompilerFlags(fout, this->ConfigName, language);
- this->WriteCompilerDefinitions(fout, this->ConfigName, language);
- this->WriteIncludes(fout, this->ConfigName, language);
- this->WriteTargetLinkLine(fout, this->ConfigName);
- this->WriteCustomCommands(fout);
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
+ this->WriteTargetSpecifics(fout, this->ConfigName);
+ this->SetCompilerFlags(this->ConfigName, language);
+ this->WriteCompilerFlags(fout, this->ConfigName, language);
+ this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+ this->WriteIncludes(fout, this->ConfigName, language);
+ this->WriteTargetLinkLine(fout, this->ConfigName);
+ this->WriteBuildEvents(fout);
+ }
this->WriteSources(fout);
- this->WriteReferences(fout);
fout.Close();
}
@@ -224,7 +235,7 @@ void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
if (flagsByLangI != this->FlagsByLanguage.end()) {
if (!flagsByLangI->second.empty()) {
std::vector<std::string> ghsCompFlags =
- cmSystemTools::ParseArguments(flagsByLangI->second.c_str());
+ cmSystemTools::ParseArguments(flagsByLangI->second);
for (auto& f : ghsCompFlags) {
fout << " " << f << std::endl;
}
@@ -238,10 +249,8 @@ void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
std::vector<std::string> compileDefinitions;
this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
language);
- for (std::vector<std::string>::const_iterator cdI =
- compileDefinitions.begin();
- cdI != compileDefinitions.end(); ++cdI) {
- fout << " -D" << (*cdI) << std::endl;
+ for (std::string const& compileDefinition : compileDefinitions) {
+ fout << " -D" << compileDefinition << std::endl;
}
}
@@ -253,9 +262,8 @@ void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
language, config);
- for (std::vector<std::string>::const_iterator includes_i = includes.begin();
- includes_i != includes.end(); ++includes_i) {
- fout << " -I\"" << *includes_i << "\"" << std::endl;
+ for (std::string const& include : includes) {
+ fout << " -I\"" << include << "\"" << std::endl;
}
}
@@ -282,16 +290,14 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
frameworkPath, linkPath, this->GeneratorTarget);
// write out link options
- std::vector<std::string> lopts =
- cmSystemTools::ParseArguments(linkFlags.c_str());
+ std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
for (auto& l : lopts) {
fout << " " << l << std::endl;
}
// write out link search paths
// must be quoted for paths that contain spaces
- std::vector<std::string> lpath =
- cmSystemTools::ParseArguments(linkPath.c_str());
+ std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
for (auto& l : lpath) {
fout << " -L\"" << l << "\"" << std::endl;
}
@@ -301,68 +307,161 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
std::vector<std::string> llibs =
- cmSystemTools::ParseArguments(linkLibraries.c_str());
+ cmSystemTools::ParseArguments(linkLibraries);
for (auto& l : llibs) {
if (l.compare(0, 2, "-l") == 0) {
fout << " \"" << l << "\"" << std::endl;
} else {
- std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l);
+ std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
fout << " -l\"" << rl << "\"" << std::endl;
}
}
}
-void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
+void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
{
- WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
- cmTarget::PRE_BUILD);
- WriteCustomCommandsHelper(
- fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreBuildCommands(),
+ std::string("prebuild"), std::string("preexecShell"));
+
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreLinkCommands(),
+ std::string("prelink"), std::string("preexecShell"));
+ }
+
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPostBuildCommands(),
+ std::string("postbuild"), std::string("postexecShell"));
+}
+
+void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
+ std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd)
+{
+ int cmdcount = 0;
+
+ for (cmCustomCommand const& cc : ccv) {
+ cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
+ // Open the filestream for this custom command
+ std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname +=
+ "/" + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_" + name;
+ fname += std::to_string(cmdcount++);
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ fout << " :" << cmd << "=\"" << fname << "\"" << std::endl;
+ } else {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << fname << ".rule\"" << std::endl;
+ }
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ }
}
void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType const commandType)
+ std::ostream& fout, cmCustomCommandGenerator const& ccg)
{
- for (std::vector<cmCustomCommand>::const_iterator commandsSetI =
- commandsSet.begin();
- commandsSetI != commandsSet.end(); ++commandsSetI) {
- cmCustomCommandLines const& commands = commandsSetI->GetCommandLines();
- for (cmCustomCommandLines::const_iterator commandI = commands.begin();
- commandI != commands.end(); ++commandI) {
- switch (commandType) {
- case cmTarget::PRE_BUILD:
- fout << " :preexecShellSafe=";
- break;
- case cmTarget::POST_BUILD:
- fout << " :postexecShellSafe=";
- break;
- default:
- assert("Only pre and post are supported");
- }
- cmCustomCommandLine const& command = *commandI;
- for (cmCustomCommandLine::const_iterator commandLineI = command.begin();
- commandLineI != command.end(); ++commandLineI) {
- std::string subCommandE =
- this->LocalGenerator->EscapeForShell(*commandLineI, true);
- if (!command.empty()) {
- fout << (command.begin() == commandLineI ? "'" : " ");
- // Need to double escape backslashes
- cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
+ std::vector<std::string> cmdLines;
+
+ // if the command specified a working directory use it.
+ std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ std::string currentBinDir = dir;
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+
+ // Line to check for error between commands.
+#ifdef _WIN32
+ std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
+#else
+ std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+#endif
+
+#ifdef _WIN32
+ cmdLines.push_back("@echo off");
+#endif
+ // Echo the custom command's comment text.
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ std::string echocmd = "echo ";
+ echocmd += comment;
+ cmdLines.push_back(std::move(echocmd));
+ }
+
+ // Switch to working directory
+ std::string cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd = cdStr +
+ this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
+ cmdLines.push_back(std::move(cdCmd));
+
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd = ccg.GetCommand(c);
+ if (!cmd.empty()) {
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands in the WindowsShell.
+ //
+ bool useCall = false;
+
+ if (this->CmdWindowsShell) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
}
- fout << subCommandE;
}
- if (!command.empty()) {
- fout << "'" << std::endl;
+
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ bool had_slash = cmd.find('/') != std::string::npos;
+ if (workingDir.empty()) {
+ cmd =
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, cmd);
+ }
+ bool has_slash = cmd.find('/') != std::string::npos;
+ if (had_slash && !has_slash) {
+ // This command was specified as a path to a file in the
+ // current directory. Add a leading "./" so it can run
+ // without the current directory being in the search path.
+ cmd = "./" + cmd;
}
+ cmd = this->LocalGenerator->ConvertToOutputFormat(
+ cmd, cmOutputConverter::SHELL);
+ if (useCall) {
+ cmd = "call " + cmd;
+ }
+ ccg.AppendArguments(c, cmd);
+ cmdLines.push_back(std::move(cmd));
}
}
+
+ // push back the custom commands
+ for (auto const& c : cmdLines) {
+ fout << c << std::endl;
+ fout << check_error << std::endl;
+ }
}
-void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
- const cmSourceFile* sf,
- std::string propName,
- std::string propFlag)
+void cmGhsMultiTargetGenerator::WriteSourceProperty(
+ std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
+ std::string const& propFlag)
{
const char* prop = sf->GetProperty(propName);
if (prop) {
@@ -393,12 +492,12 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
std::string gn = sourceGroup->GetFullName();
groupFiles[gn].push_back(sf);
- groupNames.insert(gn);
+ groupNames.insert(std::move(gn));
}
/* list of known groups and the order they are displayed in a project file */
const std::vector<std::string> standardGroups = {
- "Header Files", "Source Files", "CMake Rules",
+ "CMake Rules", "Header Files", "Source Files",
"Object Files", "Object Libraries", "Resources"
};
@@ -416,11 +515,19 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
groupFilesList[i] = *n;
i += 1;
groupNames.erase(gn);
+ } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ gn == "CMake Rules") {
+ /* make sure that rules folder always exists in case of custom targets
+ * that have no custom commands except for pre or post build events.
+ */
+ groupFilesList.resize(groupFilesList.size() + 1);
+ groupFilesList[i] = gn;
+ i += 1;
}
}
{ /* catch-all group - is last item */
- std::string gn = "";
+ std::string gn;
auto n = groupNames.find(gn);
if (n != groupNames.end()) {
groupFilesList.back() = *n;
@@ -446,7 +553,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
/* write files into the proper project file
* -- groups go into main project file
- * unless FOLDER property or variable is set.
+ * unless NO_SOURCE_GROUP_FILE property or variable is set.
*/
for (auto& sg : groupFilesList) {
std::ostream* fout;
@@ -469,7 +576,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
fpath += "/";
fpath += lpath;
- cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
+ cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
f->SetCopyIfDifferent(true);
gfiles.push_back(f);
fout = f;
@@ -485,33 +592,98 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
} else {
*fout << "{comment} " << sg << std::endl;
}
+ } else if (sg.empty()) {
+ *fout << "{comment} Others" << std::endl;
}
- /* output rule for each source file */
- for (const cmSourceFile* si : groupFiles[sg]) {
-
- // Convert filename to native system
- // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
- // windows when opening some files from the search window.
- std::string fname(si->GetFullPath());
- cmSystemTools::ConvertToOutputSlashes(fname);
- *fout << fname << std::endl;
+ if (sg != "CMake Rules") {
+ /* output rule for each source file */
+ for (const cmSourceFile* si : groupFiles[sg]) {
+ bool compile = true;
+ // Convert filename to native system
+ // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+ // windows when opening some files from the search window.
+ std::string fname(si->GetFullPath());
+ cmSystemTools::ConvertToOutputSlashes(fname);
+
+ /* For custom targets list any associated sources,
+ * comment out source code to prevent it from being
+ * compiled when processing this target.
+ * Otherwise, comment out any custom command (main) dependencies that
+ * are listed as source files to prevent them from being considered
+ * part of the build.
+ */
+ std::string comment;
+ if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ !si->GetLanguage().empty()) ||
+ si->GetCustomCommand()) {
+ comment = "{comment} ";
+ compile = false;
+ }
- if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
- "bsp" != si->GetExtension()) {
- this->WriteObjectLangOverride(*fout, si);
+ *fout << comment << fname << std::endl;
+ if (compile) {
+ if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+ "bsp" != si->GetExtension()) {
+ WriteObjectLangOverride(*fout, si);
+ }
+
+ this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+ this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+ this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
+
+ /* to avoid clutter in the GUI only print out the objectName if it
+ * has been renamed */
+ std::string objectName = this->GeneratorTarget->GetObjectName(si);
+ if (!objectName.empty() &&
+ this->GeneratorTarget->HasExplicitObjectName(si)) {
+ *fout << " -o " << objectName << std::endl;
+ }
+ }
}
-
- this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
- this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
- this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
-
- /* to avoid clutter in the gui only print out the objectName if it has
- * been renamed */
- std::string objectName = this->GeneratorTarget->GetObjectName(si);
- if (!objectName.empty() &&
- this->GeneratorTarget->HasExplicitObjectName(si)) {
- *fout << " -o " << objectName << std::endl;
+ } else {
+ std::vector<cmSourceFile const*> customCommands;
+ if (ComputeCustomCommandOrder(customCommands)) {
+ std::string message = "The custom commands for target [" +
+ this->GeneratorTarget->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ /* Custom targets do not have a dependency on SOURCES files.
+ * Therefore the dependency list may include SOURCES files after the
+ * custom target. Because nothing can depend on the custom target just
+ * move it to the last item.
+ */
+ for (auto sf = customCommands.begin(); sf != customCommands.end();
+ ++sf) {
+ if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
+ std::rotate(sf, sf + 1, customCommands.end());
+ break;
+ }
+ }
+ int cmdcount = 0;
+ for (auto& sf : customCommands) {
+ const cmCustomCommand* cc = sf->GetCustomCommand();
+ cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+ this->LocalGenerator);
+
+ // Open the filestream for this custom command
+ std::string fname =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname += "/" +
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_cc";
+ fname += std::to_string(cmdcount++) + "_";
+ fname += (sf->GetLocation()).GetName();
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ this->WriteCustomCommandLine(*fout, fname, ccg);
+ }
+ }
+ if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEvents(*fout);
}
}
}
@@ -521,62 +693,107 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
}
}
+void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
+ std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
+{
+ /* NOTE: Customization Files are not well documented. Testing showed
+ * that ":outputName=file" can only be used once per script. The
+ * script will only run if ":outputName=file" is missing or just run
+ * once if ":outputName=file" is not specified. If there are
+ * multiple outputs then the script needs to be listed multiple times
+ * for each output. Otherwise it won't rerun the script if one of
+ * the outputs is manually deleted.
+ */
+ bool specifyExtra = true;
+ for (auto& out : ccg.GetOutputs()) {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << out << "\"" << std::endl;
+ if (specifyExtra) {
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ for (auto& dep : ccg.GetDepends()) {
+ fout << " :depends=\"" << dep << "\"" << std::endl;
+ }
+ specifyExtra = false;
+ }
+ }
+}
+
void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
std::ostream& fout, const cmSourceFile* sourceFile)
{
const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
- if (NULL != rawLangProp) {
+ if (nullptr != rawLangProp) {
std::string sourceLangProp(rawLangProp);
- std::string extension(sourceFile->GetExtension());
+ std::string const& extension = sourceFile->GetExtension();
if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
fout << " -dotciscxx" << std::endl;
}
}
}
-void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
+bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
{
- // This only applies to INTEGRITY Applications
- if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
- return;
+ const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
+ if (p) {
+ return cmSystemTools::IsOn(
+ this->GeneratorTarget->GetProperty("ghs_integrity_app"));
}
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+ for (auto& sf : sources) {
+ if ("int" == sf->GetExtension()) {
+ return true;
+ }
+ }
+ return false;
+}
- // Get the targets that this one depends upon
- cmTargetDependSet unordered =
- this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
- cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
- this->Name);
- for (auto& t : ordered) {
- std::string tname = t->GetName();
- std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
- std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
- std::string outpath =
- this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
- tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
+ std::vector<cmSourceFile const*>& order)
+{
+ std::set<cmSourceFile const*> temp;
+ std::set<cmSourceFile const*> perm;
- fout << outpath;
- fout << " ";
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
+ // Collect all custom commands for this target
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
- // Tell the global generator that a refernce project needs to be created
- t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
+ for (cmSourceFile const* si : customCommands) {
+ bool r = VisitCustomCommand(temp, perm, order, si);
+ if (r) {
+ return r;
+ }
}
+ return false;
}
-bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
+bool cmGhsMultiTargetGenerator::VisitCustomCommand(
+ std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
{
- const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
- if (p) {
- return cmSystemTools::IsOn(
- this->GeneratorTarget->GetProperty("ghs_integrity_app"));
- } else {
- std::vector<cmSourceFile*> sources;
- this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
- for (auto& sf : sources) {
- if ("int" == sf->GetExtension()) {
- return true;
+ /* check if permanent mark is set*/
+ 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);
+ /* if sf exists then visit */
+ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
+ return true;
+ }
}
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(si);
+ order.push_back(si);
+ return false;
}
- return false;
+ /* revisiting item - not a DAG */
+ return true;
}
+ /* already complete */
+ return false;
}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
index a241cc6bd..a131567c8 100644
--- a/Source/cmGhsMultiTargetGenerator.h
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -5,10 +5,14 @@
#include "cmGhsMultiGpj.h"
-#include "cmTarget.h"
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
class cmCustomCommand;
-class cmGeneratedFileStream;
+class cmCustomCommandGenerator;
class cmGeneratorTarget;
class cmGlobalGhsMultiGenerator;
class cmLocalGhsMultiGenerator;
@@ -45,18 +49,27 @@ private:
void WriteIncludes(std::ostream& fout, const std::string& config,
const std::string& language);
void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
- void WriteCustomCommands(std::ostream& fout);
- void WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType commandType);
+ void WriteBuildEvents(std::ostream& fout);
+ void WriteBuildEventsHelper(std::ostream& fout,
+ const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd);
+ void WriteCustomCommandsHelper(std::ostream& fout,
+ cmCustomCommandGenerator const& ccg);
+ void WriteCustomCommandLine(std::ostream& fout, std::string& fname,
+ cmCustomCommandGenerator const& ccg);
+ bool ComputeCustomCommandOrder(std::vector<cmSourceFile const*>& order);
+ bool VisitCustomCommand(std::set<cmSourceFile const*>& temp,
+ std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order,
+ cmSourceFile const* sf);
void WriteSources(std::ostream& fout_proj);
void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
- std::string propName, std::string propFlag);
- void WriteReferences(std::ostream& fout);
+ std::string const& propName,
+ std::string const& propFlag);
static void WriteObjectLangOverride(std::ostream& fout,
const cmSourceFile* sourceFile);
- bool DetermineIfIntegrityApp(void);
+ bool DetermineIfIntegrityApp();
cmGeneratorTarget* GeneratorTarget;
cmLocalGhsMultiGenerator* LocalGenerator;
cmMakefile* Makefile;
@@ -66,7 +79,8 @@ private:
std::string TargetNameReal;
GhsMultiGpj::Types TagType;
std::string const Name;
- std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ bool const CmdWindowsShell; /* custom commands run in cmd.exe or /bin/sh */
};
#endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
index 5fd890eab..9fb417098 100644
--- a/Source/cmGlobVerificationManager.cxx
+++ b/Source/cmGlobVerificationManager.cxx
@@ -25,8 +25,8 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
cmGeneratedFileStream verifyScriptFile(scriptFile);
verifyScriptFile.SetCopyIfDifferent(true);
if (!verifyScriptFile) {
- cmSystemTools::Error("Unable to open verification script file for save. ",
- scriptFile.c_str());
+ cmSystemTools::Error("Unable to open verification script file for save. " +
+ scriptFile);
cmSystemTools::ReportLastSystemError("");
return false;
}
@@ -71,8 +71,8 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
cmsys::ofstream verifyStampFile(stampFile.c_str());
if (!verifyStampFile) {
- cmSystemTools::Error("Unable to open verification stamp file for write. ",
- stampFile.c_str());
+ cmSystemTools::Error("Unable to open verification stamp file for write. " +
+ stampFile);
return false;
}
verifyStampFile << "# This file is generated by CMake for checking of the "
diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h
index f7146bec0..48606d3f3 100644
--- a/Source/cmGlobVerificationManager.h
+++ b/Source/cmGlobVerificationManager.h
@@ -22,11 +22,11 @@
class cmGlobVerificationManager
{
protected:
- ///! Save verification script for given makefile.
- ///! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
+ //! Save verification script for given makefile.
+ //! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
bool SaveVerificationScript(const std::string& path);
- ///! Add an entry into the glob cache
+ //! Add an entry into the glob cache
void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
const std::string& relative,
const std::string& expression,
@@ -34,13 +34,13 @@ protected:
const std::string& variable,
const cmListFileBacktrace& bt);
- ///! Clear the glob cache for state reset.
+ //! Clear the glob cache for state reset.
void Reset();
- ///! Check targets should be written in generated build system.
+ //! Check targets should be written in generated build system.
bool DoWriteVerifyTarget() const;
- ///! Get the paths to the generated script and stamp files
+ //! Get the paths to the generated script and stamp files
std::string const& GetVerifyScript() const { return this->VerifyScript; }
std::string const& GetVerifyStamp() const { return this->VerifyStamp; }
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index c2eb583a9..51d681dee 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -34,7 +34,7 @@ void cmGlobalBorlandMakefileGenerator::EnableLanguage(
this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -53,15 +53,16 @@ void cmGlobalBorlandMakefileGenerator::GetDocumentation(
entry.Brief = "Generates Borland makefiles.";
}
-void cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index ca04b7b73..ee7de70f6 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -22,7 +22,7 @@ public:
cmGlobalBorlandMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalBorlandMakefileGenerator::GetActualName();
@@ -32,7 +32,7 @@ public:
/** Get the documentation entry for this generator. */
static void GetDocumentation(cmDocumentationEntry& entry);
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -46,15 +46,12 @@ public:
bool AllowDeleteOnError() const override { return false; }
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8a3720fe6..4eba4ff93 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -7,6 +7,7 @@
#include <algorithm>
#include <assert.h>
#include <cstring>
+#include <initializer_list>
#include <iterator>
#include <sstream>
#include <stdio.h>
@@ -34,6 +35,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
@@ -211,7 +213,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
if (!mf->GetDefinition(langComp)) {
if (!optional) {
- cmSystemTools::Error(langComp.c_str(), " not set, after EnableLanguage");
+ cmSystemTools::Error(langComp + " not set, after EnableLanguage");
}
return;
}
@@ -270,8 +272,7 @@ void cmGlobalGenerator::AddBuildExportExportSet(
bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
{
- std::map<std::string, cmExportBuildFileGenerator*>::iterator it =
- this->BuildExportSets.find(file);
+ auto const it = this->BuildExportSets.find(file);
if (it != this->BuildExportSets.end()) {
bool result = it->second->GenerateImportFile();
@@ -297,10 +298,7 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
{
bool failed = false;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& targets =
- localGen->GetGeneratorTargets();
-
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
target->GetType() == cmStateEnums::TargetType::UTILITY ||
@@ -314,9 +312,11 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
if (configs.empty()) {
target->GetSourceFiles(srcs, "");
} else {
- for (std::vector<std::string>::const_iterator ci = configs.begin();
- ci != configs.end() && srcs.empty(); ++ci) {
- target->GetSourceFiles(srcs, *ci);
+ for (std::string const& config : configs) {
+ target->GetSourceFiles(srcs, config);
+ if (srcs.empty()) {
+ break;
+ }
}
}
if (srcs.empty()) {
@@ -331,11 +331,41 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
return failed;
}
+bool cmGlobalGenerator::CheckTargetsForType() const
+{
+ if (!this->GetLanguageEnabled("Swift")) {
+ return false;
+ }
+ bool failed = false;
+ for (cmLocalGenerator* generator : this->LocalGenerators) {
+ for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
+ std::vector<std::string> configs;
+ target->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.emplace_back();
+ }
+
+ for (std::string const& config : configs) {
+ if (target->GetLinkerLanguage(config) == "Swift") {
+ if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "WIN32_EXECUTABLE property is not supported on Swift "
+ "executables",
+ target->GetBacktrace());
+ failed = true;
+ }
+ }
+ }
+ }
+ }
+ return failed;
+}
+
bool cmGlobalGenerator::IsExportedTargetsFile(
const std::string& filename) const
{
- const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
- this->BuildExportSets.find(filename);
+ auto const it = this->BuildExportSets.find(filename);
if (it == this->BuildExportSets.end()) {
return false;
}
@@ -536,11 +566,22 @@ void cmGlobalGenerator::EnableLanguage(
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
-# pragma warning(disable : 4996)
+# ifdef __INTEL_COMPILER
+# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# else
+# pragma warning(disable : 4996)
+# endif
# endif
GetVersionExW((OSVERSIONINFOW*)&osviex);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
std::ostringstream windowsVersionString;
windowsVersionString << osviex.dwMajorVersion << "."
@@ -635,8 +676,7 @@ void cmGlobalGenerator::EnableLanguage(
// to avoid duplicate compiler tests.
if (cmSystemTools::FileExists(fpath)) {
if (!mf->ReadListFile(fpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
}
// if this file was found then the language was already determined
// to be working
@@ -661,8 +701,8 @@ void cmGlobalGenerator::EnableLanguage(
determineCompiler += "Compiler.cmake";
std::string determineFile = mf->GetModulesFile(determineCompiler);
if (!mf->ReadListFile(determineFile)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- determineCompiler.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " +
+ determineCompiler);
}
if (cmSystemTools::GetFatalErrorOccured()) {
return;
@@ -680,8 +720,9 @@ void cmGlobalGenerator::EnableLanguage(
std::string compilerEnv = "CMAKE_";
compilerEnv += lang;
compilerEnv += "_COMPILER_ENV_VAR";
- std::string envVar = mf->GetRequiredDefinition(compilerEnv);
- std::string envVarValue = mf->GetRequiredDefinition(compilerName);
+ const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
+ const std::string& envVarValue =
+ mf->GetRequiredDefinition(compilerName);
std::string env = envVar;
env += "=";
env += envVarValue;
@@ -695,8 +736,7 @@ void cmGlobalGenerator::EnableLanguage(
fpath += lang;
fpath += "Compiler.cmake";
if (!mf->ReadListFile(fpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
}
this->SetLanguageEnabledFlag(lang, mf);
needSetLanguageEnabledMaps[lang] = true;
@@ -788,11 +828,10 @@ void cmGlobalGenerator::EnableLanguage(
fpath += "Information.cmake";
std::string informationFile = mf->GetModulesFile(fpath);
if (informationFile.empty()) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
} else if (!mf->ReadListFile(informationFile)) {
- cmSystemTools::Error("Could not process cmake module file: ",
- informationFile.c_str());
+ cmSystemTools::Error("Could not process cmake module file: " +
+ informationFile);
}
}
if (needSetLanguageEnabledMaps[lang]) {
@@ -812,8 +851,8 @@ void cmGlobalGenerator::EnableLanguage(
testLang += "Compiler.cmake";
std::string ifpath = mf->GetModulesFile(testLang);
if (!mf->ReadListFile(ifpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- testLang.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " +
+ testLang);
}
std::string compilerWorks = "CMAKE_";
compilerWorks += lang;
@@ -898,7 +937,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
"Converting " << lang <<
- " compiler id \"AppleClang\" to \"Clang\" for compatibility."
+ R"( compiler id "AppleClang" to "Clang" for compatibility.)"
;
/* clang-format on */
mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -928,7 +967,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
"Converting " << lang <<
- " compiler id \"QCC\" to \"GNU\" for compatibility."
+ R"( compiler id "QCC" to "GNU" for compatibility.)"
;
/* clang-format on */
mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -954,6 +993,36 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
break;
}
}
+
+ if (strcmp(compilerId, "XLClang") == 0) {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
+ "Converting " << lang <<
+ R"( compiler id "XLClang" to "XL" for compatibility.)"
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to convert XLClang to XL.
+ mf->AddDefinition(compilerIdVar, "XL");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep AppleClang.
+ break;
+ }
+ }
}
std::string cmGlobalGenerator::GetLanguageOutputExtension(
@@ -961,9 +1030,7 @@ std::string cmGlobalGenerator::GetLanguageOutputExtension(
{
const std::string& lang = source.GetLanguage();
if (!lang.empty()) {
- std::map<std::string, std::string>::const_iterator it =
- this->LanguageToOutputExtension.find(lang);
-
+ auto const it = this->LanguageToOutputExtension.find(lang);
if (it != this->LanguageToOutputExtension.end()) {
return it->second;
}
@@ -988,8 +1055,7 @@ std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
if (ext && *ext == '.') {
++ext;
}
- std::map<std::string, std::string>::const_iterator it =
- this->ExtensionToLanguage.find(ext);
+ auto const it = this->ExtensionToLanguage.find(ext);
if (it != this->ExtensionToLanguage.end()) {
return it->second;
}
@@ -1182,14 +1248,16 @@ void cmGlobalGenerator::Configure()
this->ConfigureDoneCMP0026AndCMP0024 = true;
// Put a copy of each global target in every directory.
- std::vector<GlobalTargetInfo> globalTargets;
- this->CreateDefaultGlobalTargets(globalTargets);
-
- for (cmMakefile* mf : this->Makefiles) {
- cmTargets* targets = &(mf->GetTargets());
- for (GlobalTargetInfo const& globalTarget : globalTargets) {
- targets->insert(cmTargets::value_type(
- globalTarget.Name, this->CreateGlobalTarget(globalTarget, mf)));
+ {
+ std::vector<GlobalTargetInfo> globalTargets;
+ this->CreateDefaultGlobalTargets(globalTargets);
+
+ for (cmMakefile* mf : this->Makefiles) {
+ auto& targets = mf->GetTargets();
+ for (GlobalTargetInfo const& globalTarget : globalTargets) {
+ targets.emplace(globalTarget.Name,
+ this->CreateGlobalTarget(globalTarget, mf));
+ }
}
}
@@ -1222,7 +1290,7 @@ void cmGlobalGenerator::Configure()
} else {
msg << "Configuring done";
}
- this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1);
+ this->CMakeInstance->UpdateProgress(msg.str(), -1);
}
}
@@ -1238,7 +1306,7 @@ void cmGlobalGenerator::CreateImportedGenerationObjects(
std::vector<const cmGeneratorTarget*>& exports)
{
this->CreateGenerationObjects(ImportedOnly);
- std::vector<cmMakefile*>::iterator mfit =
+ auto const mfit =
std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
cmLocalGenerator* lg =
this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
@@ -1253,8 +1321,7 @@ void cmGlobalGenerator::CreateImportedGenerationObjects(
cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
const std::string& filename) const
{
- std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
- this->BuildExportSets.find(filename);
+ auto const it = this->BuildExportSets.find(filename);
return it == this->BuildExportSets.end() ? nullptr : it->second;
}
@@ -1347,7 +1414,9 @@ bool cmGlobalGenerator::Compute()
for (cmLocalGenerator* localGen : this->LocalGenerators) {
cmMakefile* mf = localGen->GetMakefile();
for (cmInstallGenerator* g : mf->GetInstallGenerators()) {
- g->Compute(localGen);
+ if (!g->Compute(localGen)) {
+ return false;
+ }
}
}
@@ -1376,6 +1445,10 @@ bool cmGlobalGenerator::Compute()
return false;
}
+ if (this->CheckTargetsForType()) {
+ return false;
+ }
+
for (cmLocalGenerator* localGen : this->LocalGenerators) {
localGen->ComputeHomeRelativeOutputPath();
}
@@ -1468,8 +1541,7 @@ bool cmGlobalGenerator::ComputeTargetDepends()
if (!ctd.Compute()) {
return false;
}
- std::vector<cmGeneratorTarget const*> const& targets = ctd.GetTargets();
- for (cmGeneratorTarget const* target : targets) {
+ for (cmGeneratorTarget const* target : ctd.GetTargets()) {
ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
}
return true;
@@ -1509,8 +1581,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
const cmBacktraceRange noconfig_compile_definitions_bts =
mf->GetCompileDefinitionsBacktraces();
- cmTargets& targets = mf->GetTargets();
- for (auto& target : targets) {
+ for (auto& target : mf->GetTargets()) {
cmTarget* t = &target.second;
if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
continue;
@@ -1522,12 +1593,12 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
continue;
}
- cmBacktraceRange::const_iterator btIt =
- noconfig_compile_definitions_bts.begin();
- for (cmStringRange::const_iterator it =
- noconfig_compile_definitions.begin();
- it != noconfig_compile_definitions.end(); ++it, ++btIt) {
- t->InsertCompileDefinition(*it, *btIt);
+ {
+ auto btIt = noconfig_compile_definitions_bts.begin();
+ auto it = noconfig_compile_definitions.begin();
+ for (; it != noconfig_compile_definitions.end(); ++it, ++btIt) {
+ t->InsertCompileDefinition(*it, *btIt);
+ }
}
cmPolicies::PolicyStatus polSt =
@@ -1567,17 +1638,14 @@ void cmGlobalGenerator::CreateGeneratorTargets(
std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
{
if (targetTypes == AllTargets) {
- cmTargets& targets = mf->GetTargets();
- for (auto& target : targets) {
+ for (auto& target : mf->GetTargets()) {
cmTarget* t = &target.second;
cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
lg->AddGeneratorTarget(gt);
}
}
- std::vector<cmTarget*> itgts = mf->GetImportedTargets();
-
- for (cmTarget* t : itgts) {
+ for (cmTarget* t : mf->GetImportedTargets()) {
lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
}
}
@@ -1613,6 +1681,7 @@ void cmGlobalGenerator::ClearGeneratorMembers()
cmDeleteAll(this->LocalGenerators);
this->LocalGenerators.clear();
+ this->AliasTargets.clear();
this->ExportSets.clear();
this->TargetDependencies.clear();
this->TargetSearchIndex.clear();
@@ -1638,14 +1707,11 @@ void cmGlobalGenerator::CheckTargetProperties()
cmState* state = this->GetCMakeInstance()->GetState();
for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
this->Makefiles[i]->ConfigureFinalPass();
- cmTargets& targets = this->Makefiles[i]->GetTargets();
- for (auto const& target : targets) {
+ for (auto const& target : this->Makefiles[i]->GetTargets()) {
if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- const cmTarget::LinkLibraryVectorType& libs =
- target.second.GetOriginalLinkLibraries();
- for (auto const& lib : libs) {
+ for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
if (lib.first.size() > 9 &&
cmSystemTools::IsNOTFOUND(lib.first.c_str())) {
std::string varName = lib.first.substr(0, lib.first.size() - 9);
@@ -1702,8 +1768,8 @@ void cmGlobalGenerator::CheckTargetProperties()
cmSystemTools::Error("The following variables are used in this project, "
"but they are set to NOTFOUND.\n"
"Please set them or make sure they are set and "
- "tested correctly in the CMake files:\n",
- notFoundVars.c_str());
+ "tested correctly in the CMake files:\n" +
+ notFoundVars);
}
}
@@ -1731,20 +1797,9 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
this->FirstTimeProgress);
}
- std::string newTarget;
+ std::vector<std::string> newTarget = {};
if (!target.empty()) {
- newTarget += target;
-#if 0
-# if defined(_WIN32) || defined(__CYGWIN__)
- std::string tmp = target;
- // if the target does not already end in . something
- // then assume .exe
- if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
- {
- newTarget += ".exe";
- }
-# endif // WIN32
-#endif
+ newTarget = { target };
}
std::string config =
mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
@@ -1752,14 +1807,16 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
config, false, fast, false, this->TryCompileTimeout);
}
-void cmGlobalGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& /*unused*/,
- const std::string& /*unused*/, const std::string& /*unused*/,
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGenerator::GenerateBuildCommand(
const std::string& /*unused*/, const std::string& /*unused*/,
- bool /*unused*/, int /*unused*/, bool /*unused*/,
- std::vector<std::string> const& /*unused*/)
+ const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
+ const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
+ bool /*unused*/, std::vector<std::string> const& /*unused*/)
{
- makeCommand.add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+ return { std::move(makeCommand) };
}
void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
@@ -1769,15 +1826,13 @@ void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
// they do not support certain build command line options
}
-int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
- const std::string& bindir,
- const std::string& projectName,
- const std::string& target, std::string& output,
- const std::string& makeCommandCSTR,
- const std::string& config, bool clean, bool fast,
- bool verbose, cmDuration timeout,
- cmSystemTools::OutputOption outputflag,
- std::vector<std::string> const& nativeOptions)
+int cmGlobalGenerator::Build(
+ int jobs, const std::string& /*unused*/, const std::string& bindir,
+ const std::string& projectName, const std::vector<std::string>& targets,
+ std::string& output, const std::string& makeCommandCSTR,
+ const std::string& config, bool clean, bool fast, bool verbose,
+ cmDuration timeout, cmSystemTools::OutputOption outputflag,
+ std::vector<std::string> const& nativeOptions)
{
bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
@@ -1790,40 +1845,45 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
output += "\n";
if (workdir.Failed()) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
- cmSystemTools::Error("Failed to change directory: ",
- std::strerror(workdir.GetLastResult()));
- output += "Failed to change directory: ";
- output += std::strerror(workdir.GetLastResult());
+ std::string err = "Failed to change directory: ";
+ err += std::strerror(workdir.GetLastResult());
+ cmSystemTools::Error(err);
+ output += err;
output += "\n";
return 1;
}
- int retVal;
+ int retVal = 0;
cmSystemTools::SetRunCommandHideConsole(true);
std::string outputBuffer;
std::string* outputPtr = &outputBuffer;
- GeneratedMakeCommand makeCommand;
- this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
- target, config, fast, jobs, verbose,
- nativeOptions);
+ std::vector<GeneratedMakeCommand> makeCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
+ config, fast, jobs, verbose, nativeOptions);
// Workaround to convince some commands to produce output.
if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
- makeCommand.RequiresOutputForward) {
+ makeCommand.back().RequiresOutputForward) {
outputflag = cmSystemTools::OUTPUT_FORWARD;
}
// should we do a clean first?
if (clean) {
- GeneratedMakeCommand cleanCommand;
- this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
- bindir, "clean", config, fast, jobs, verbose);
+ std::vector<GeneratedMakeCommand> cleanCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
+ { "clean" }, config, fast, jobs, verbose);
output += "\nRun Clean Command:";
- output += cleanCommand.printable();
+ output += cleanCommand.front().Printable();
output += "\n";
-
- if (!cmSystemTools::RunSingleCommand(cleanCommand.PrimaryCommand,
+ if (cleanCommand.size() != 1) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
+ "The generator did not produce "
+ "exactly one command for the "
+ "'clean' target");
+ return 1;
+ }
+ if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
outputPtr, outputPtr, &retVal,
nullptr, outputflag, timeout)) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
@@ -1837,33 +1897,34 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
}
// now build
- std::string makeCommandStr = makeCommand.printable();
+ std::string makeCommandStr;
output += "\nRun Build Command(s):";
- output += makeCommandStr;
- output += "\n";
- if (!cmSystemTools::RunSingleCommand(makeCommand.PrimaryCommand, outputPtr,
- outputPtr, &retVal, nullptr, outputflag,
- timeout)) {
- cmSystemTools::SetRunCommandHideConsole(hideconsole);
- cmSystemTools::Error(
- "Generator: execution of make failed. Make command was: ",
- makeCommandStr.c_str());
- output += *outputPtr;
- output += "\nGenerator: execution of make failed. Make command was: " +
- makeCommandStr + "\n";
+ for (auto command = makeCommand.begin(); command != makeCommand.end();
+ ++command) {
+ makeCommandStr = command->Printable();
+ if (command != makeCommand.end()) {
+ makeCommandStr += " && ";
+ }
- return 1;
- }
- output += *outputPtr;
- cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ output += makeCommandStr;
+ if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
+ outputPtr, &retVal, nullptr,
+ outputflag, timeout)) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error(
+ "Generator: execution of make failed. Make command was: " +
+ makeCommandStr);
+ output += *outputPtr;
+ output += "\nGenerator: execution of make failed. Make command was: " +
+ makeCommandStr + "\n";
- // The SGI MipsPro 7.3 compiler does not return an error code when
- // the source has a #error in it! This is a work-around for such
- // compilers.
- if ((retVal == 0) && (output.find("#error") != std::string::npos)) {
- retVal = 1;
+ return 1;
+ }
+ output += *outputPtr;
}
+ output += "\n";
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
// The OpenWatcom tools do not return an error code when a link
// library is not found!
@@ -2029,18 +2090,10 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
return this->IsExcluded(rootSnp, snp);
}
-bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
- cmGeneratorTarget* target) const
+bool cmGlobalGenerator::IsExcluded(cmGeneratorTarget* target) const
{
- if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
- return true;
- }
- if (const char* exclude = target->GetProperty("EXCLUDE_FROM_ALL")) {
- return cmSystemTools::IsOn(exclude);
- }
- // This target is included in its directory. Check whether the
- // directory is excluded.
- return this->IsExcluded(root, target->GetLocalGenerator());
+ return target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetPropertyAsBool("EXCLUDE_FROM_ALL");
}
void cmGlobalGenerator::GetEnabledLanguages(
@@ -2051,8 +2104,7 @@ void cmGlobalGenerator::GetEnabledLanguages(
int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
{
- std::map<std::string, int>::const_iterator it =
- this->LanguageToLinkerPreference.find(lang);
+ auto const it = this->LanguageToLinkerPreference.find(lang);
if (it != this->LanguageToLinkerPreference.end()) {
return it->second;
}
@@ -2079,9 +2131,9 @@ void cmGlobalGenerator::FillProjectMap()
cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
{
- MakefileMap::const_iterator i = this->MakefileSearchIndex.find(start_dir);
- if (i != this->MakefileSearchIndex.end()) {
- return i->second;
+ auto const it = this->MakefileSearchIndex.find(start_dir);
+ if (it != this->MakefileSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2089,10 +2141,9 @@ cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
cmDirectoryId const& id) const
{
- LocalGeneratorMap::const_iterator i =
- this->LocalGeneratorSearchIndex.find(id.String);
- if (i != this->LocalGeneratorSearchIndex.end()) {
- return i->second;
+ auto const it = this->LocalGeneratorSearchIndex.find(id.String);
+ if (it != this->LocalGeneratorSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2122,17 +2173,24 @@ void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
}
}
+static char const hexDigits[] = "0123456789abcdef";
+
std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
cmGeneratorTarget const* gt)
{
// Use the pointer value to uniquely identify the target instance.
- // Use a "T" prefix to indicate that this identifier is for a target.
+ // Use a ":" prefix to avoid conflict with project-defined targets.
// We must satisfy cmGeneratorExpression::IsValidTargetName so use no
// other special characters.
- char buf[64];
- sprintf(buf, "::T%p",
- static_cast<void const*>(gt)); // cast avoids format warning
- std::string id = gt->GetName() + buf;
+ char buf[1 + sizeof(gt) * 2];
+ char* b = buf;
+ *b++ = ':';
+ for (size_t i = 0; i < sizeof(gt); ++i) {
+ unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
+ *b++ = hexDigits[(c & 0xf0) >> 4];
+ *b++ = hexDigits[(c & 0x0f)];
+ }
+ std::string id(buf, sizeof(buf));
// We internally index pointers to non-const generator targets
// but our callers only have pointers to const generator targets.
// They will give up non-const privileges when looking up anyway.
@@ -2159,9 +2217,9 @@ void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
{
- TargetMap::const_iterator i = this->TargetSearchIndex.find(name);
- if (i != this->TargetSearchIndex.end()) {
- return i->second;
+ auto const it = this->TargetSearchIndex.find(name);
+ if (it != this->TargetSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2169,10 +2227,9 @@ cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
std::string const& name) const
{
- GeneratorTargetMap::const_iterator i =
- this->GeneratorTargetSearchIndex.find(name);
- if (i != this->GeneratorTargetSearchIndex.end()) {
- return i->second;
+ auto const it = this->GeneratorTargetSearchIndex.find(name);
+ if (it != this->GeneratorTargetSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2181,8 +2238,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
bool excludeAliases) const
{
if (!excludeAliases) {
- std::map<std::string, std::string>::const_iterator ai =
- this->AliasTargets.find(name);
+ auto const ai = this->AliasTargets.find(name);
if (ai != this->AliasTargets.end()) {
return this->FindTargetImpl(ai->second);
}
@@ -2193,8 +2249,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
const std::string& name) const
{
- std::map<std::string, std::string>::const_iterator ai =
- this->AliasTargets.find(name);
+ auto const ai = this->AliasTargets.find(name);
if (ai != this->AliasTargets.end()) {
return this->FindGeneratorTargetImpl(ai->second);
}
@@ -2204,7 +2259,7 @@ cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
bool cmGlobalGenerator::NameResolvesToFramework(
const std::string& libname) const
{
- if (cmSystemTools::IsPathToFramework(libname.c_str())) {
+ if (cmSystemTools::IsPathToFramework(libname)) {
return true;
}
@@ -2285,10 +2340,9 @@ void cmGlobalGenerator::AddGlobalTarget_Package(
return;
}
- const char* reservedTargets[] = { "package", "PACKAGE" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CPack packaging is enabled")) {
+ static const auto reservedTargets = { "package", "PACKAGE" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
return;
}
}
@@ -2335,10 +2389,10 @@ void cmGlobalGenerator::AddGlobalTarget_PackageSource(
return;
}
- const char* reservedTargets[] = { "package_source" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CPack source packaging is enabled")) {
+ static const auto reservedTargets = { "package_source" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target,
+ "when CPack source packaging is enabled")) {
return;
}
}
@@ -2365,10 +2419,9 @@ void cmGlobalGenerator::AddGlobalTarget_Test(
return;
}
- const char* reservedTargets[] = { "test", "RUN_TESTS" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CTest testing is enabled")) {
+ static const auto reservedTargets = { "test", "RUN_TESTS" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
return;
}
}
@@ -2627,8 +2680,7 @@ bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
std::string const& l) const
{
- std::map<std::string, std::string>::const_iterator it =
- this->LanguageToOriginalSharedLibFlags.find(l);
+ auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
if (it != this->LanguageToOriginalSharedLibFlags.end()) {
return it->second;
}
@@ -2706,11 +2758,8 @@ void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets,
if (this->IsExcluded(root, generator)) {
continue;
}
- // Get the targets in the makefile
- const std::vector<cmGeneratorTarget*>& tgts =
- generator->GetGeneratorTargets();
- // loop over all the targets
- for (cmGeneratorTarget* target : tgts) {
+ // loop over all the generator targets in the makefile
+ for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
if (this->IsRootOnlyTarget(target) &&
target->GetLocalGenerator() != root) {
continue;
@@ -2736,8 +2785,7 @@ void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
if (projectTargets.insert(target).second) {
// This is the first time we have encountered the target.
// Recursively follow its dependencies.
- TargetDependSet const& ts = this->GetTargetDirectDepends(target);
- for (auto const& t : ts) {
+ for (auto const& t : this->GetTargetDirectDepends(target)) {
this->AddTargetDepends(t, projectTargets);
}
}
@@ -2849,8 +2897,7 @@ void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
fname = line.substr(33);
// Look for a hash for this file's rule.
- std::map<std::string, RuleHash>::const_iterator rhi =
- this->RuleHashes.find(fname);
+ auto const rhi = this->RuleHashes.find(fname);
if (rhi != this->RuleHashes.end()) {
// Compare the rule hash in the file to that we were given.
if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
@@ -2900,8 +2947,7 @@ void cmGlobalGenerator::WriteSummary()
cmGeneratedFileStream fout(fname);
for (cmLocalGenerator* lg : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : tgts) {
+ for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -2989,12 +3035,9 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
for (std::string const& c : configs) {
target->GetSourceFiles(sources, c);
}
- std::vector<cmSourceFile*>::const_iterator sourcesEnd =
- cmRemoveDuplicates(sources);
- for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
- si != sourcesEnd; ++si) {
+ auto const sourcesEnd = cmRemoveDuplicates(sources);
+ for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
Json::Value& lj_source = lj_sources.append(Json::objectValue);
- cmSourceFile* sf = *si;
std::string const& sfp = sf->GetFullPath();
fout << sfp << "\n";
lj_source["file"] = sfp;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 0e40610d4..db964892a 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmCustomCommandLines.h"
#include "cmDuration.h"
#include "cmExportSetMap.h"
@@ -56,33 +57,20 @@ struct GeneratedMakeCommand
{
// Add each argument as a separate element to the vector
template <typename... T>
- void add(T&&... args)
+ void Add(T&&... args)
{
// iterate the args and append each one
AppendStrs(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,
+ void Add(std::vector<std::string>::const_iterator start,
std::vector<std::string>::const_iterator end)
{
- PrimaryCommand.insert(PrimaryCommand.end(), start, end);
+ cmAppend(PrimaryCommand, start, end);
}
- std::string printable() const
- {
- std::size_t size = PrimaryCommand.size();
- for (auto&& i : PrimaryCommand) {
- size += i.size();
- }
- std::string buffer;
- buffer.reserve(size);
- for (auto&& i : PrimaryCommand) {
- buffer.append(i);
- buffer.append(1, ' ');
- }
- return buffer;
- }
+ std::string Printable() const { return cmJoin(PrimaryCommand, " "); }
std::vector<std::string> PrimaryCommand;
bool RequiresOutputForward = false;
@@ -98,13 +86,13 @@ struct GeneratedMakeCommand
class cmGlobalGenerator
{
public:
- ///! Free any memory allocated with the GlobalGenerator
+ //! Free any memory allocated with the GlobalGenerator
cmGlobalGenerator(cmake* cm);
virtual ~cmGlobalGenerator();
virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
- ///! Get the name for this generator
+ //! Get the name for this generator
virtual std::string GetName() const { return "Generic"; }
/** Check whether the given name matches the current generator. */
@@ -216,10 +204,10 @@ public:
*/
int Build(
int jobs, const std::string& srcdir, const std::string& bindir,
- const std::string& projectName, const std::string& targetName,
- std::string& output, const std::string& makeProgram,
- const std::string& config, bool clean, bool fast, bool verbose,
- cmDuration timeout,
+ const std::string& projectName,
+ std::vector<std::string> const& targetNames, std::string& output,
+ const std::string& makeProgram, const std::string& config, bool clean,
+ bool fast, bool verbose, cmDuration timeout,
cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
std::vector<std::string> const& nativeOptions =
std::vector<std::string>());
@@ -234,11 +222,10 @@ public:
{
};
- virtual void GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose,
+ virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
std::vector<std::string> const& makeOptions = std::vector<std::string>());
virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
@@ -249,7 +236,7 @@ public:
const std::string& native,
bool ignoreErrors);
- ///! Get the CMake instance
+ //! Get the CMake instance
cmake* GetCMakeInstance() const { return this->CMakeInstance; }
void SetConfiguredFilesPath(cmGlobalGenerator* gen);
@@ -274,7 +261,7 @@ public:
void AddMakefile(cmMakefile* mf);
- ///! Set an generator for an "external makefile based project"
+ //! Set an generator for an "external makefile based project"
void SetExternalMakefileProjectGenerator(
cmExternalMakefileProjectGenerator* extraGenerator);
@@ -303,19 +290,19 @@ public:
bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
- ///! return the language for the given extension
+ //! return the language for the given extension
std::string GetLanguageFromExtension(const char* ext) const;
- ///! is an extension to be ignored
+ //! is an extension to be ignored
bool IgnoreFile(const char* ext) const;
- ///! What is the preference for linkers and this language (None or Preferred)
+ //! What is the preference for linkers and this language (None or Preferred)
int GetLinkerPreference(const std::string& lang) const;
- ///! What is the object file extension for a given source file?
+ //! What is the object file extension for a given source file?
std::string GetLanguageOutputExtension(cmSourceFile const&) const;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
virtual const char* GetCMakeCFGIntDir() const { return "."; }
- ///! expand CFGIntDir for a configuration
+ //! expand CFGIntDir for a configuration
virtual std::string ExpandCFGIntDir(const std::string& str,
const std::string& config) const;
@@ -331,7 +318,7 @@ public:
*/
virtual bool FindMakeProgram(cmMakefile*);
- ///! Find a target by name by searching the local generators.
+ //! Find a target by name by searching the local generators.
cmTarget* FindTarget(const std::string& name,
bool excludeAliases = false) const;
@@ -522,7 +509,7 @@ protected:
bool IsExcluded(cmStateSnapshot const& root,
cmStateSnapshot const& snp) const;
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
- bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
+ bool IsExcluded(cmGeneratorTarget* target) const;
virtual void InitializeProgressMarks() {}
struct GlobalTargetInfo
@@ -622,6 +609,7 @@ private:
virtual void ForceLinkerLanguages();
bool CheckTargetsForMissingSources() const;
+ bool CheckTargetsForType() const;
void CreateLocalGenerators();
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 45fa0529f..b69dea038 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -2,22 +2,33 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalGhsMultiGenerator.h"
-#include "cmsys/SystemTools.hxx"
-
-#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
-#include "cmGhsMultiTargetGenerator.h"
+#include "cmGhsMultiGpj.h"
+#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
#include "cmVersion.h"
#include "cmake.h"
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <string.h>
+#include <utility>
+
const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+#ifdef __linux__
+const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs";
+#elif defined(_WIN32)
const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs";
+#endif
cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
: cmGlobalGenerator(cm)
@@ -25,9 +36,7 @@ cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
cm->GetState()->SetGhsMultiIDE(true);
}
-cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
-{
-}
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
cmMakefile* mf)
@@ -64,7 +73,8 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
/* no toolset was found */
if (tsp.empty()) {
return false;
- } else if (ts.empty()) {
+ }
+ if (ts.empty()) {
std::string message;
message =
"Green Hills MULTI: -T <toolset> not specified; defaulting to \"";
@@ -86,7 +96,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
/* check if the toolset changed from last generate */
- if (prevTool != NULL && (gbuild != prevTool)) {
+ if (prevTool != nullptr && (gbuild != prevTool)) {
std::string message = "toolset build tool: ";
message += gbuild;
message += "\nDoes not match the previously used build tool: ";
@@ -95,13 +105,12 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
"directory or choose a different binary directory.";
cmSystemTools::Error(message);
return false;
- } else {
- /* store the toolset that is being used for this build */
- mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
- "build program to use", cmStateEnums::INTERNAL,
- true);
}
+ /* store the toolset that is being used for this build */
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
+ "build program to use", cmStateEnums::INTERNAL, true);
+
mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str());
return true;
@@ -110,10 +119,11 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
cmMakefile* mf)
{
- if (p == "") {
+ std::string arch;
+ if (p.empty()) {
cmSystemTools::Message(
"Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\"");
- std::string arch = "arm";
+ arch = "arm";
/* store the platform name for later use
* -- already done if -A<arch> was specified
@@ -121,19 +131,51 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(),
"Name of generator platform.",
cmStateEnums::INTERNAL);
+ } else {
+ arch = p;
}
- const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
- if (tgtPlatform == nullptr) {
- cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
- "specified; defaulting to \"integrity\"");
- tgtPlatform = "integrity";
+ /* check if OS location has been updated by platform scripts */
+ std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM");
+ std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR");
+ if (cmSystemTools::IsOff(osdir.c_str()) &&
+ platform.find("integrity") != std::string::npos) {
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ /* required OS location is not found */
+ std::string m =
+ "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \"";
+ m += mf->GetSafeDefinition("GHS_OS_ROOT");
+ m += "\"";
+ cmSystemTools::Message(m);
+ }
+ osdir = "GHS_OS_DIR-NOT-SPECIFIED";
+ } else if (!this->CMakeInstance->GetIsInTryCompile() &&
+ cmSystemTools::IsOff(this->OsDir) &&
+ !cmSystemTools::IsOff(osdir)) {
+ /* OS location was updated by auto-selection */
+ std::string m = "Green Hills MULTI: GHS_OS_DIR not specified; found \"";
+ m += osdir;
+ m += "\"";
+ cmSystemTools::Message(m);
}
+ this->OsDir = osdir;
- /* store the platform name for later use */
- mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
- "Name of GHS target platform.",
- cmStateEnums::INTERNAL);
+ // Determine GHS_BSP_NAME
+ std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME");
+
+ if (cmSystemTools::IsOff(bspName.c_str()) &&
+ platform.find("integrity") != std::string::npos) {
+ bspName = "sim" + arch;
+ /* write back the calculate name for next time */
+ mf->AddCacheDefinition("GHS_BSP_NAME", bspName.c_str(),
+ "Name of GHS target platform.",
+ cmStateEnums::STRING, true);
+ std::string m =
+ "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \"";
+ m += bspName;
+ m += "\"";
+ cmSystemTools::Message(m);
+ }
return true;
}
@@ -144,6 +186,21 @@ void cmGlobalGhsMultiGenerator::EnableLanguage(
mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+
+ const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
+ if (!tgtPlatform) {
+ cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
+ "specified; defaulting to \"integrity\"");
+ tgtPlatform = "integrity";
+ }
+
+ /* store the platform name for later use */
+ mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
+ "Name of GHS target platform.", cmStateEnums::STRING);
+
+ /* store original OS location */
+ this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR");
+
this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
}
@@ -185,8 +242,7 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
}
} else {
std::string tryPath;
- /* CollapseCombinedPath will check if ts is an absolute path */
- tryPath = cmSystemTools::CollapseCombinedPath(tsd, ts);
+ tryPath = cmSystemTools::CollapseFullPath(ts, tsd);
if (!cmSystemTools::FileExists(tryPath)) {
std::string msg = "GHS toolset \"" + tryPath + "\" not found.";
cmSystemTools::Error(msg);
@@ -202,139 +258,246 @@ void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
fout << "#!gbuild" << std::endl;
fout << "#" << std::endl
<< "# CMAKE generated file: DO NOT EDIT!" << std::endl
- << "# Generated by \"" << this->GetActualName() << "\""
+ << "# Generated by \"" << GetActualName() << "\""
<< " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
<< cmVersion::GetMinorVersion() << std::endl
<< "#" << std::endl
<< std::endl;
}
-void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
{
- WriteFileHeader(fout);
+ fout << "Commands {\n"
+ " Custom_Rule_Command {\n"
+ " name = \"Custom Rule Command\"\n"
+ " exec = \"";
+#ifdef _WIN32
+ fout << "cmd.exe";
+#else
+ fout << "/bin/sh";
+#endif
+ fout << "\"\n"
+ " options = {\"SpecialOptions\"}\n"
+ " }\n"
+ "}\n";
+
+ fout << "\n\n";
+ fout << "FileTypes {\n"
+ " CmakeRule {\n"
+ " name = \"Custom Rule\"\n"
+ " action = \"&Run\"\n"
+ " extensions = {\"";
+#ifdef _WIN32
+ fout << "bat";
+#else
+ fout << "sh";
+#endif
+ fout << "\"}\n"
+ " grepable = false\n"
+ " command = \"Custom Rule Command\"\n"
+ " commandLine = \"$COMMAND ";
+#ifdef _WIN32
+ fout << "/c";
+#endif
+ fout << " $INPUTFILE\"\n"
+ " progress = \"Processing Custom Rule\"\n"
+ " promoteToFirstPass = true\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
+{
+ fout << "FileTypes {\n"
+ " CmakeTarget {\n"
+ " name = \"Custom Target\"\n"
+ " action = \"&Execute\"\n"
+ " grepable = false\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
- this->WriteMacros(fout);
- this->WriteHighLevelDirectives(fout);
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
+ cmLocalGenerator* root)
+{
+ this->WriteFileHeader(fout);
+ this->WriteMacros(fout, root);
+ this->WriteHighLevelDirectives(root, fout);
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
fout << "# Top Level Project File" << std::endl;
// Specify BSP option if supplied by user
- // -- not all platforms require this entry in the project file
- // integrity platforms require this field; use default if needed
- std::string platform;
- if (const char* p =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) {
- platform = p;
- }
-
- std::string bspName;
- if (char const* bspCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) {
- bspName = bspCache;
- this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
- } else {
- bspName = "IGNORE";
- }
-
- if (platform.find("integrity") != std::string::npos &&
- cmSystemTools::IsOff(bspName.c_str())) {
- const char* a =
- this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
- bspName = "sim";
- bspName += (a ? a : "");
- }
-
- if (!cmSystemTools::IsOff(bspName.c_str())) {
+ const char* bspName =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+ if (!cmSystemTools::IsOff(bspName)) {
fout << " -bsp " << bspName << std::endl;
}
// Specify OS DIR if supplied by user
// -- not all platforms require this entry in the project file
- std::string osDir;
- std::string osDirOption;
- if (char const* osDirCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) {
- osDir = osDirCache;
+ if (!cmSystemTools::IsOff(this->OsDir.c_str())) {
+ const char* osDirOption =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION");
+ std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/');
+ fout << " ";
+ if (cmSystemTools::IsOff(osDirOption)) {
+ fout << "";
+ } else {
+ fout << osDirOption;
+ }
+ fout << "\"" << this->OsDir << "\"" << std::endl;
}
+}
- if (char const* osDirOptionCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) {
- osDirOption = osDirOptionCache;
+void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
+ std::string& all_target)
+{
+ fout << "CMakeFiles/" << all_target << " [Project]" << std::endl;
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
+ continue;
+ }
+ fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
+ << " [Project]" << std::endl;
}
+}
- if (!cmSystemTools::IsOff(osDir.c_str()) ||
- platform.find("integrity") != std::string::npos) {
- std::replace(osDir.begin(), osDir.end(), '\\', '/');
- fout << " " << osDirOption << "\"" << osDir << "\"" << std::endl;
+void cmGlobalGhsMultiGenerator::WriteProjectLine(
+ std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root,
+ std::string& rootBinaryDir)
+{
+ const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
+ const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (projName && projType) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+ if (dir == ".") {
+ dir.clear();
+ } else {
+ if (dir.back() != '/') {
+ dir += "/";
+ }
+ }
+
+ std::string projFile = dir + projName + FILE_EXTENSION;
+ fout << projFile;
+ fout << " " << projType << std::endl;
+ } else {
+ /* Should never happen */
+ std::string message =
+ "The project file for target [" + target->GetName() + "] is missing.\n";
+ cmSystemTools::Error(message);
+ fout << "{comment} " << target->GetName() << " [missing project file]\n";
}
+}
+
+void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
+{
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
+ continue;
+ }
- WriteSubProjects(fout, root, generators);
+ // create target build file
+ std::string name = target->GetName() + ".tgt" + FILE_EXTENSION;
+ std::string fname = rootBinaryDir + "/" + name;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(target, build)) {
+ std::string message = "The inter-target dependency graph for target [" +
+ target->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ for (auto& tgt : build) {
+ WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+ }
+ }
+ fbld.Close();
+ }
}
-void cmGlobalGhsMultiGenerator::WriteSubProjects(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteAllTarget(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target)
{
+ this->ProjectTargets.clear();
+
+ // create target build file
+ all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
+ ".tgt" + FILE_EXTENSION;
+ std::string fname =
+ root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+
// Collect all targets under this root generator and the transitive
// closure of their dependencies.
TargetDependSet projectTargets;
TargetDependSet originalTargets;
this->GetTargetSets(projectTargets, originalTargets, root, generators);
- OrderedTargetDependSet orderedProjectTargets(projectTargets, "");
-
- // write out all the sub-projects
- std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
- for (cmGeneratorTarget const* target : orderedProjectTargets) {
- if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
+ std::vector<cmGeneratorTarget const*> defaultTargets;
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ /* save list of all targets in sorted order */
+ this->ProjectTargets.push_back(t);
+ }
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
-
- const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
- const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
- if (projName && projType) {
- cmLocalGenerator* lg = target->GetLocalGenerator();
- std::string dir = lg->GetCurrentBinaryDirectory();
- dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir.c_str());
- if (dir == ".") {
- dir.clear();
- } else {
- if (dir.back() != '/') {
- dir += "/";
- }
- }
-
- if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) {
- fout << "{comment} ";
- }
- std::string projFile = dir + projName + FILE_EXTENSION;
- fout << projFile;
- fout << " " << projType << std::endl;
-
- if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) {
- // create reference project
- std::string fname = dir;
- fname += target->GetName();
- fname += "REF";
- fname += FILE_EXTENSION;
-
- cmGeneratedFileStream fref(fname.c_str());
- fref.SetCopyIfDifferent(true);
-
- this->WriteFileHeader(fref);
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref);
- fref << " :reference=" << projFile << std::endl;
-
- fref.Close();
+ if (!cmSystemTools::IsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) {
+ defaultTargets.push_back(t);
+ }
+ }
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(defaultTargets, build)) {
+ std::string message = "The inter-target dependency graph for project [" +
+ root->GetProjectName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ // determine the targets for ALL target
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+ for (cmGeneratorTarget const* target : build) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ continue;
}
+ this->WriteProjectLine(fbld, target, root, rootBinaryDir);
}
}
+ fbld.Close();
}
void cmGlobalGhsMultiGenerator::Generate()
{
+ std::string fname;
+
// first do the superclass method
this->cmGlobalGenerator::Generate();
@@ -342,11 +505,32 @@ void cmGlobalGhsMultiGenerator::Generate()
for (auto& it : this->ProjectMap) {
this->OutputTopLevelProject(it.second[0], it.second);
}
+
+ // create custom rule BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_rule.bod";
+ cmGeneratedFileStream frule(fname);
+ frule.SetCopyIfDifferent(true);
+ this->WriteFileHeader(frule);
+ this->WriteCustomRuleBOD(frule);
+ frule.Close();
+
+ // create custom target BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_target.bod";
+ cmGeneratedFileStream ftarget(fname);
+ ftarget.SetCopyIfDifferent(true);
+ this->WriteFileHeader(ftarget);
+ this->WriteCustomTargetBOD(ftarget);
+ ftarget.Close();
}
void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
{
+ std::string fname;
+ std::string all_target;
+
if (generators.empty()) {
return;
}
@@ -355,86 +539,106 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
* with target projects. This avoid the issue where the project has
* the same name as the executable target.
*/
- std::string fname = root->GetCurrentBinaryDirectory();
+ fname = root->GetCurrentBinaryDirectory();
fname += "/";
fname += root->GetProjectName();
fname += ".top";
fname += FILE_EXTENSION;
- cmGeneratedFileStream fout(fname.c_str());
- fout.SetCopyIfDifferent(true);
+ cmGeneratedFileStream top(fname);
+ top.SetCopyIfDifferent(true);
+ this->WriteTopLevelProject(top, root);
- this->WriteTopLevelProject(fout, root, generators);
+ this->WriteAllTarget(root, generators, all_target);
+ this->WriteTargets(root);
- fout.Close();
+ this->WriteSubProjects(top, all_target);
+ top.Close();
}
-void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
- int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGhsMultiGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
- const char* gbuild =
- this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
- makeCommand.add(this->SelectMakeProgram(makeProgram, (std::string)gbuild));
+ GeneratedMakeCommand makeCommand = {};
+ std::string gbuild;
+ if (const char* gbuildCached =
+ this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
+ gbuild = gbuildCached;
+ }
+ makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-parallel");
+ makeCommand.Add("-parallel");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
/* determine which top-project file to use */
std::string proj = projectName + ".top" + FILE_EXTENSION;
std::vector<std::string> files;
cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
if (!files.empty()) {
+ /* if multiple top-projects are found in build directory
+ * then prefer projectName top-project.
+ */
auto p = std::find(files.begin(), files.end(), proj);
if (p == files.end()) {
proj = files.at(0);
}
}
- makeCommand.add("-top", proj);
- if (!targetName.empty()) {
- if (targetName == "clean") {
- makeCommand.add("-clean");
+ makeCommand.Add("-top", proj);
+ if (!targetNames.empty()) {
+ if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+ targetNames.end()) {
+ makeCommand.Add("-clean");
} else {
- if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) {
- makeCommand.add(targetName);
- } else {
- makeCommand.add(targetName + ".gpj");
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname + ".tgt.gpj");
+ }
}
}
+ } else {
+ /* transform name to default build */;
+ std::string all = proj;
+ all.replace(all.end() - 7, all.end(),
+ std::string(this->GetAllTargetName()) + ".tgt.gpj");
+ makeCommand.Add(all);
}
+ return { makeCommand };
}
-void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
+ cmLocalGenerator* root)
{
+ fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl;
char const* ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
- if (NULL != ghsGpjMacros) {
+ if (nullptr != ghsGpjMacros) {
std::vector<std::string> expandedList;
cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
- for (std::vector<std::string>::const_iterator expandedListI =
- expandedList.begin();
- expandedListI != expandedList.end(); ++expandedListI) {
- fout << "macro " << *expandedListI << std::endl;
+ for (std::string const& arg : expandedList) {
+ fout << "macro " << arg << std::endl;
}
}
}
-void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
+ cmLocalGenerator* root, std::ostream& fout)
{
/* set primary target */
std::string tgt;
const char* t =
this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
- if (t) {
+ if (t && *t != '\0') {
tgt = t;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
} else {
@@ -449,16 +653,20 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
}
fout << "primaryTarget=" << tgt << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_rule.bod" << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_target.bod" << std::endl;
char const* const customization =
this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
- if (NULL != customization && strlen(customization) > 0) {
- fout << "customization=" << trimQuotes(customization) << std::endl;
+ if (nullptr != customization && strlen(customization) > 0) {
+ fout << "customization=" << this->TrimQuotes(customization) << std::endl;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
-std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
+std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str)
{
std::string result;
result.reserve(str.size());
@@ -491,3 +699,56 @@ cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
{
this->insert(targets.begin(), targets.end());
}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
+{
+ std::vector<cmGeneratorTarget const*> t{ tgt };
+ return ComputeTargetBuildOrder(t, build);
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build)
+{
+ std::set<cmGeneratorTarget const*> temp;
+ std::set<cmGeneratorTarget const*> perm;
+
+ for (auto ti : tgt) {
+ bool r = VisitTarget(temp, perm, build, ti);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGlobalGhsMultiGenerator::VisitTarget(
+ std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(ti) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(ti).second) {
+ /* sort targets lexicographically to ensure that nodes are always visited
+ * in the same order */
+ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
+ "");
+ for (auto& di : sortedTargets) {
+ if (this->VisitTarget(temp, perm, order, di)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(ti);
+ order.push_back(ti);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index bc2b199a0..98358c74d 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -5,10 +5,20 @@
#include "cmGlobalGenerator.h"
-#include "cmGhsMultiGpj.h"
#include "cmGlobalGeneratorFactory.h"
+#include "cmTargetDepend.h"
-class cmGeneratedFileStream;
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmake;
+struct cmDocumentationEntry;
class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
{
@@ -17,21 +27,21 @@ public:
static const char* FILE_EXTENSION;
cmGlobalGhsMultiGenerator(cmake* cm);
- ~cmGlobalGhsMultiGenerator();
+ ~cmGlobalGhsMultiGenerator() override;
static cmGlobalGeneratorFactory* NewFactory()
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
}
- ///! create the correct local generator
+ //! create the correct local generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/// @return the name of this generator.
static std::string GetActualName() { return "Green Hills MULTI"; }
- ///! Get the name for this generator
- std::string GetName() const override { return this->GetActualName(); }
+ //! Get the name for this generator
+ std::string GetName() const override { return GetActualName(); }
/// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
static void GetDocumentation(cmDocumentationEntry& entry);
@@ -68,7 +78,54 @@ public:
// Write the common disclaimer text at the top of each build file.
void WriteFileHeader(std::ostream& fout);
- // Target dependency sorting
+ const char* GetInstallTargetName() const override { return "install"; }
+
+protected:
+ void Generate() override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+private:
+ void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
+
+ /* top-level project */
+ void OutputTopLevelProject(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
+ void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
+ void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
+ void WriteSubProjects(std::ostream& fout, std::string& all_target);
+ void WriteTargets(cmLocalGenerator* root);
+ void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
+ cmLocalGenerator* root, std::string& rootBinaryDir);
+ void WriteCustomRuleBOD(std::ostream& fout);
+ void WriteCustomTargetBOD(std::ostream& fout);
+ void WriteAllTarget(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target);
+
+ std::string TrimQuotes(std::string const& str);
+
+ std::string OsDir;
+ static const char* DEFAULT_BUILD_PROGRAM;
+ static const char* DEFAULT_TOOLSET_ROOT;
+
+ bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool ComputeTargetBuildOrder(std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool VisitTarget(std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order,
+ cmGeneratorTarget const* ti);
+
+ std::vector<cmGeneratorTarget const*> ProjectTargets;
+
+ // Target sorting
class TargetSet : public std::set<cmGeneratorTarget const*>
{
};
@@ -77,44 +134,14 @@ public:
std::string First;
public:
- TargetCompare(std::string const& first)
- : First(first)
+ TargetCompare(std::string first)
+ : First(std::move(first))
{
}
bool operator()(cmGeneratorTarget const* l,
cmGeneratorTarget const* r) const;
};
class OrderedTargetDependSet;
-
-protected:
- void Generate() override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
-
-private:
- void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
-
- /* top-level project */
- void OutputTopLevelProject(cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
- void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
- void WriteMacros(std::ostream& fout);
- void WriteHighLevelDirectives(std::ostream& fout);
- void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
-
- std::string trimQuotes(std::string const& str);
-
- static const char* DEFAULT_BUILD_PROGRAM;
- static const char* DEFAULT_TOOLSET_ROOT;
};
class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 2b7f48695..ff5428868 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -54,19 +54,19 @@ void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
-void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::vector<std::string> jomMakeOptions;
// Since we have full control over the invocation of JOM, let us
// make it quiet.
jomMakeOptions.push_back(this->MakeSilentFlag);
- jomMakeOptions.insert(jomMakeOptions.end(), makeOptions.begin(),
- makeOptions.end());
+ cmAppend(jomMakeOptions, makeOptions);
// JOM does parallel builds by default, the -j is only needed if a specific
// number is given
@@ -75,7 +75,7 @@ void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
}
- cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, jobs, verbose, jomMakeOptions);
+ return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, jomMakeOptions);
}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index aa8b5fbb0..df3aec9b4 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -20,7 +20,7 @@ public:
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalJOMMakefileGenerator::GetActualName();
@@ -40,15 +40,12 @@ public:
bool optional) override;
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
private:
void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index 3c2455662..7b5838909 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -45,9 +45,10 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage(
std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
this->FindMakeProgram(mf);
- std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::vector<std::string> locations;
- std::string makeloc = cmSystemTools::GetProgramPath(makeProgram.c_str());
+ std::string makeloc = cmSystemTools::GetProgramPath(makeProgram);
locations.push_back(this->FindMinGW(makeloc));
locations.push_back(makeloc);
locations.push_back("/mingw/bin");
@@ -76,8 +77,8 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage(
if (!mf->IsSet("CMAKE_AR") && !this->CMakeInstance->GetIsInTryCompile() &&
!(1 == l.size() && l[0] == "NONE")) {
cmSystemTools::Error(
- "CMAKE_AR was not found, please set to archive program. ",
- mf->GetDefinition("CMAKE_AR"));
+ "CMAKE_AR was not found, please set to archive program. " +
+ mf->GetSafeDefinition("CMAKE_AR"));
}
}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
index 23dbc5e31..d6e4847fe 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.h
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -19,7 +19,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
virtual std::string GetName() const
{
return cmGlobalMSYSMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index c6d46e936..e218b4b95 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -23,7 +23,8 @@ void cmGlobalMinGWMakefileGenerator::EnableLanguage(
std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
this->FindMakeProgram(mf);
- std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::vector<std::string> locations;
locations.push_back(cmSystemTools::GetProgramPath(makeProgram));
locations.push_back("/mingw/bin");
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
index a994c9295..15297e3c7 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.h
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -19,7 +19,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<
cmGlobalMinGWMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
virtual std::string GetName() const
{
return cmGlobalMinGWMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index ffe95f905..2273c00ac 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -54,23 +54,23 @@ void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
-void cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::vector<std::string> nmakeMakeOptions;
// Since we have full control over the invocation of nmake, let us
// make it quiet.
nmakeMakeOptions.push_back(this->MakeSilentFlag);
- nmakeMakeOptions.insert(nmakeMakeOptions.end(), makeOptions.begin(),
- makeOptions.end());
+ cmAppend(nmakeMakeOptions, makeOptions);
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
}
void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 06c48e22b..2fdf1ce5d 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -21,7 +21,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<
cmGlobalNMakeMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalNMakeMakefileGenerator::GetActualName();
@@ -45,15 +45,12 @@ public:
bool optional) override;
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 920f6393c..2d52356bc 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -26,6 +26,7 @@
#include "cmMessageType.h"
#include "cmNinjaLinkLineComputer.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -126,164 +127,163 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path)
return result;
}
-void cmGlobalNinjaGenerator::WriteBuild(
- std::ostream& os, const std::string& comment, const std::string& rule,
- const cmNinjaDeps& outputs, const cmNinjaDeps& implicitOuts,
- const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables,
- const std::string& rspfile, int cmdLineLimit, bool* usedResponseFile)
+void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
+ cmNinjaBuild const& build,
+ int cmdLineLimit,
+ bool* usedResponseFile)
{
// Make sure there is a rule.
- if (rule.empty()) {
- cmSystemTools::Error("No rule for WriteBuildStatement! called "
- "with comment: ",
- comment.c_str());
+ if (build.Rule.empty()) {
+ cmSystemTools::Error("No rule for WriteBuild! called with comment: " +
+ build.Comment);
return;
}
// Make sure there is at least one output file.
- if (outputs.empty()) {
- cmSystemTools::Error("No output files for WriteBuildStatement! called "
- "with comment: ",
- comment.c_str());
+ if (build.Outputs.empty()) {
+ cmSystemTools::Error(
+ "No output files for WriteBuild! called with comment: " + build.Comment);
return;
}
- cmGlobalNinjaGenerator::WriteComment(os, comment);
-
- std::string arguments;
-
- // TODO: Better formatting for when there are multiple input/output files.
+ cmGlobalNinjaGenerator::WriteComment(os, build.Comment);
- // Write explicit dependencies.
- for (std::string const& explicitDep : explicitDeps) {
- arguments += " " + EncodePath(explicitDep);
- }
-
- // Write implicit dependencies.
- if (!implicitDeps.empty()) {
- arguments += " |";
- for (std::string const& implicitDep : implicitDeps) {
- arguments += " " + EncodePath(implicitDep);
+ // Write output files.
+ std::string buildStr("build");
+ {
+ // Write explicit outputs
+ for (std::string const& output : build.Outputs) {
+ buildStr += " " + EncodePath(output);
+ if (this->ComputingUnknownDependencies) {
+ this->CombinedBuildOutputs.insert(output);
+ }
}
- }
-
- // Write order-only dependencies.
- if (!orderOnlyDeps.empty()) {
- arguments += " ||";
- for (std::string const& orderOnlyDep : orderOnlyDeps) {
- arguments += " " + EncodePath(orderOnlyDep);
+ // Write implicit outputs
+ if (!build.ImplicitOuts.empty()) {
+ buildStr += " |";
+ for (std::string const& implicitOut : build.ImplicitOuts) {
+ buildStr += " " + EncodePath(implicitOut);
+ }
}
+ buildStr += ":";
+
+ // Write the rule.
+ buildStr += " ";
+ buildStr += build.Rule;
}
- arguments += "\n";
+ std::string arguments;
+ {
+ // TODO: Better formatting for when there are multiple input/output files.
- std::string build;
+ // Write explicit dependencies.
+ for (std::string const& explicitDep : build.ExplicitDeps) {
+ arguments += " " + EncodePath(explicitDep);
+ }
- // Write outputs files.
- build += "build";
- for (std::string const& output : outputs) {
- build += " " + EncodePath(output);
- if (this->ComputingUnknownDependencies) {
- this->CombinedBuildOutputs.insert(output);
+ // Write implicit dependencies.
+ if (!build.ImplicitDeps.empty()) {
+ arguments += " |";
+ for (std::string const& implicitDep : build.ImplicitDeps) {
+ arguments += " " + EncodePath(implicitDep);
+ }
}
- }
- if (!implicitOuts.empty()) {
- build += " |";
- for (std::string const& implicitOut : implicitOuts) {
- build += " " + EncodePath(implicitOut);
+
+ // Write order-only dependencies.
+ if (!build.OrderOnlyDeps.empty()) {
+ arguments += " ||";
+ for (std::string const& orderOnlyDep : build.OrderOnlyDeps) {
+ arguments += " " + EncodePath(orderOnlyDep);
+ }
}
- }
- build += ":";
- // Write the rule.
- build += " " + rule;
+ arguments += "\n";
+ }
// Write the variables bound to this build statement.
- std::ostringstream variable_assignments;
- for (auto const& variable : variables) {
- cmGlobalNinjaGenerator::WriteVariable(variable_assignments, variable.first,
- variable.second, "", 1);
- }
+ std::string assignments;
+ {
+ std::ostringstream variable_assignments;
+ for (auto const& variable : build.Variables) {
+ cmGlobalNinjaGenerator::WriteVariable(
+ variable_assignments, variable.first, variable.second, "", 1);
+ }
- // check if a response file rule should be used
- std::string buildstr = build;
- std::string assignments = variable_assignments.str();
- bool useResponseFile = false;
- if (cmdLineLimit < 0 ||
- (cmdLineLimit > 0 &&
- (arguments.size() + buildstr.size() + assignments.size() + 1000) >
- static_cast<size_t>(cmdLineLimit))) {
- variable_assignments.str(std::string());
- cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
- rspfile, "", 1);
- assignments += variable_assignments.str();
- useResponseFile = true;
- }
- if (usedResponseFile) {
- *usedResponseFile = useResponseFile;
+ // check if a response file rule should be used
+ assignments = variable_assignments.str();
+ bool useResponseFile = false;
+ if (cmdLineLimit < 0 ||
+ (cmdLineLimit > 0 &&
+ (arguments.size() + buildStr.size() + assignments.size() + 1000) >
+ static_cast<size_t>(cmdLineLimit))) {
+ variable_assignments.str(std::string());
+ cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
+ build.RspFile, "", 1);
+ assignments += variable_assignments.str();
+ useResponseFile = true;
+ }
+ if (usedResponseFile) {
+ *usedResponseFile = useResponseFile;
+ }
}
- os << buildstr << arguments << assignments;
-}
-
-void cmGlobalNinjaGenerator::WritePhonyBuild(
- std::ostream& os, const std::string& comment, const cmNinjaDeps& outputs,
- const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables)
-{
- this->WriteBuild(os, comment, "phony", outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps,
- orderOnlyDeps, variables);
+ os << buildStr << arguments << assignments << "\n";
}
void cmGlobalNinjaGenerator::AddCustomCommandRule()
{
- this->AddRule("CUSTOM_COMMAND", "$COMMAND", "$DESC",
- "Rule for running custom commands.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "", // bound on each build statement as needed
- /*generator*/ false);
+ cmNinjaRule rule("CUSTOM_COMMAND");
+ rule.Command = "$COMMAND";
+ rule.Description = "$DESC";
+ rule.Comment = "Rule for running custom commands.";
+ this->AddRule(rule);
}
void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
const std::string& command, const std::string& description,
- const std::string& comment, const std::string& depfile, bool uses_terminal,
- bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps,
- const cmNinjaDeps& orderOnly)
+ const std::string& comment, const std::string& depfile,
+ const std::string& job_pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps,
+ const cmNinjaDeps& orderOnlyDeps)
{
- std::string cmd = command; // NOLINT(*)
-#ifdef _WIN32
- if (cmd.empty())
- // TODO Shouldn't an empty command be handled by ninja?
- cmd = "cmd.exe /c";
-#endif
-
this->AddCustomCommandRule();
- cmNinjaVars vars;
- vars["COMMAND"] = cmd;
- vars["DESC"] = EncodeLiteral(description);
- if (restat) {
- vars["restat"] = "1";
- }
- if (uses_terminal && SupportsConsolePool()) {
- vars["pool"] = "console";
- }
- if (!depfile.empty()) {
- vars["depfile"] = depfile;
+ {
+ cmNinjaBuild build("CUSTOM_COMMAND");
+ build.Comment = comment;
+ build.Outputs = outputs;
+ build.ExplicitDeps = explicitDeps;
+ build.OrderOnlyDeps = orderOnlyDeps;
+
+ cmNinjaVars& vars = build.Variables;
+ {
+ std::string cmd = command; // NOLINT(*)
+#ifdef _WIN32
+ if (cmd.empty())
+ // TODO Shouldn't an empty command be handled by ninja?
+ cmd = "cmd.exe /c";
+#endif
+ vars["COMMAND"] = std::move(cmd);
+ }
+ vars["DESC"] = EncodeLiteral(description);
+ if (restat) {
+ vars["restat"] = "1";
+ }
+ if (uses_terminal && SupportsConsolePool()) {
+ vars["pool"] = "console";
+ } else if (!job_pool.empty()) {
+ vars["pool"] = job_pool;
+ }
+ if (!depfile.empty()) {
+ vars["depfile"] = depfile;
+ }
+ this->WriteBuild(*this->BuildFileStream, build);
}
- this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs,
- /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(),
- orderOnly, vars);
if (this->ComputingUnknownDependencies) {
// we need to track every dependency that comes in, since we are trying
// to find dependencies that are side effects of build commands
- for (std::string const& dep : deps) {
+ for (std::string const& dep : explicitDeps) {
this->CombinedCustomCommandExplicitDependencies.insert(dep);
}
}
@@ -291,111 +291,79 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
void cmGlobalNinjaGenerator::AddMacOSXContentRule()
{
- cmLocalGenerator* lg = this->LocalGenerators[0];
-
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -E copy $in $out";
-
- this->AddRule("COPY_OSX_CONTENT", cmd.str(), "Copying OS X Content $out",
- "Rule for copying OS X bundle content file.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("COPY_OSX_CONTENT");
+ rule.Command = 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);
}
-void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
- const std::string& output)
+void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input,
+ std::string output)
{
this->AddMacOSXContentRule();
-
- cmNinjaDeps outputs;
- outputs.push_back(output);
- cmNinjaDeps deps;
- deps.push_back(input);
- cmNinjaVars vars;
-
- this->WriteBuild(*this->BuildFileStream, "", "COPY_OSX_CONTENT", outputs,
- /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(),
- cmNinjaDeps(), cmNinjaVars());
+ {
+ cmNinjaBuild build("COPY_OSX_CONTENT");
+ build.Outputs.push_back(std::move(output));
+ build.ExplicitDeps.push_back(std::move(input));
+ this->WriteBuild(*this->BuildFileStream, build);
+ }
}
-void cmGlobalNinjaGenerator::WriteRule(
- std::ostream& os, const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
+ cmNinjaRule const& rule)
{
+ // -- Parameter checks
// Make sure the rule has a name.
- if (name.empty()) {
- cmSystemTools::Error("No name given for WriteRuleStatement! called "
- "with comment: ",
- comment.c_str());
+ if (rule.Name.empty()) {
+ cmSystemTools::Error("No name given for WriteRule! called with comment: " +
+ rule.Comment);
return;
}
// Make sure a command is given.
- if (command.empty()) {
- cmSystemTools::Error("No command given for WriteRuleStatement! called "
- "with comment: ",
- comment.c_str());
+ if (rule.Command.empty()) {
+ cmSystemTools::Error(
+ "No command given for WriteRule! called with comment: " + rule.Comment);
return;
}
- cmGlobalNinjaGenerator::WriteComment(os, comment);
-
- // Write the rule.
- os << "rule " << name << "\n";
-
- // Write the depfile if any.
- if (!depfile.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "depfile = " << depfile << "\n";
- }
-
- // Write the deptype if any.
- if (!deptype.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "deps = " << deptype << "\n";
+ // Make sure response file content is given
+ if (!rule.RspFile.empty() && rule.RspContent.empty()) {
+ cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! "
+ "called with comment: " +
+ rule.Comment);
+ return;
}
- // Write the command.
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "command = " << command << "\n";
+ // -- Write rule
+ // Write rule intro
+ cmGlobalNinjaGenerator::WriteComment(os, rule.Comment);
+ os << "rule " << rule.Name << '\n';
- // Write the description if any.
- if (!description.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "description = " << description << "\n";
- }
-
- if (!rspfile.empty()) {
- if (rspcontent.empty()) {
- cmSystemTools::Error("No rspfile_content given!", comment.c_str());
- return;
+ // Write rule key/value pairs
+ auto writeKV = [&os](const char* key, std::string const& value) {
+ if (!value.empty()) {
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << key << " = " << value << '\n';
}
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile = " << rspfile << "\n";
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile_content = " << rspcontent << "\n";
- }
+ };
- if (!restat.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "restat = " << restat << "\n";
+ writeKV("depfile", rule.DepFile);
+ writeKV("deps", rule.DepType);
+ writeKV("command", rule.Command);
+ writeKV("description", rule.Description);
+ if (!rule.RspFile.empty()) {
+ writeKV("rspfile", rule.RspFile);
+ writeKV("rspfile_content", rule.RspContent);
}
-
- if (generator) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "generator = 1\n";
+ writeKV("restat", rule.Restat);
+ if (rule.Generator) {
+ writeKV("generator", "1");
}
- os << "\n";
+ // Finish rule
+ os << '\n';
}
void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
@@ -407,8 +375,8 @@ void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
// Make sure we have a name.
if (name.empty()) {
cmSystemTools::Error("No name given for WriteVariable! called "
- "with comment: ",
- comment.c_str());
+ "with comment: " +
+ comment);
return;
}
@@ -445,9 +413,6 @@ void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
: cmGlobalCommonGenerator(cm)
- , BuildFileStream(nullptr)
- , RulesFileStream(nullptr)
- , CompileCommandsStream(nullptr)
, UsingGCCOnWindows(false)
, ComputingUnknownDependencies(false)
, PolicyCMP0058(cmPolicies::WARN)
@@ -508,8 +473,12 @@ void cmGlobalNinjaGenerator::Generate()
msg.str());
return;
}
- this->OpenBuildFileStream();
- this->OpenRulesFileStream();
+ if (!this->OpenBuildFileStream()) {
+ return;
+ }
+ if (!this->OpenRulesFileStream()) {
+ return;
+ }
this->TargetDependsClosures.clear();
@@ -591,7 +560,7 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
static std::string const k_DYNDEP_ = ".dyndep-";
std::string::size_type pos = this->NinjaVersion.find(k_DYNDEP_);
if (pos != std::string::npos) {
- const char* fv = this->NinjaVersion.c_str() + pos + k_DYNDEP_.size();
+ const char* fv = &this->NinjaVersion[pos + k_DYNDEP_.size()];
cmSystemTools::StringToULong(fv, &this->NinjaSupportsDyndeps);
}
}
@@ -656,13 +625,20 @@ void cmGlobalNinjaGenerator::EnableLanguage(
this->ResolveLanguageCompiler(l, mf, optional);
}
#ifdef _WIN32
- if ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
- (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
- (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
- (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
- (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
- (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
- (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang"))) {
+ const bool clangGnuMode =
+ ((mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_FRONTEND_VARIANT") == "GNU")) ||
+ ((mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT") == "GNU"));
+
+ if (clangGnuMode ||
+ ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
+ (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang")))) {
this->UsingGCCOnWindows = true;
}
#endif
@@ -676,59 +652,52 @@ void cmGlobalNinjaGenerator::EnableLanguage(
// cmGlobalXCodeGenerator
// Called by:
// cmGlobalGenerator::Build()
-void cmGlobalNinjaGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& /*projectName*/, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNinjaGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& /*config*/,
+ bool /*fast*/, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- makeCommand.add(this->SelectMakeProgram(makeProgram));
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
if (verbose) {
- makeCommand.add("-v");
+ makeCommand.Add("-v");
}
if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
(jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
- makeCommand.add("-j", std::to_string(jobs));
+ makeCommand.Add("-j", std::to_string(jobs));
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
- if (!targetName.empty()) {
- if (targetName == "clean") {
- makeCommand.add("-t", "clean");
- } else {
- makeCommand.add(targetName);
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname);
}
}
+ return { std::move(makeCommand) };
}
// Non-virtual public methods.
-void cmGlobalNinjaGenerator::AddRule(
- const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::AddRule(cmNinjaRule const& rule)
{
// Do not add the same rule twice.
- if (this->HasRule(name)) {
+ if (!this->Rules.insert(rule.Name).second) {
return;
}
-
- this->Rules.insert(name);
- cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command,
- description, comment, depfile, deptype,
- rspfile, rspcontent, restat, generator);
-
- this->RuleCmdLength[name] = static_cast<int>(command.size());
+ // Store command length
+ this->RuleCmdLength[rule.Name] = static_cast<int>(rule.Command.size());
+ // Write rule
+ cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, rule);
}
bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
{
- RulesSetType::const_iterator rule = this->Rules.find(name);
- return (rule != this->Rules.end());
+ return (this->Rules.find(name) != this->Rules.end());
}
// Private virtual overrides
@@ -754,7 +723,7 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
// Private methods
-void cmGlobalNinjaGenerator::OpenBuildFileStream()
+bool cmGlobalNinjaGenerator::OpenBuildFileStream()
{
// Compute Ninja's build file path.
std::string buildFilePath =
@@ -764,12 +733,12 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
// Get a stream where to generate things.
if (!this->BuildFileStream) {
- this->BuildFileStream = new cmGeneratedFileStream(
+ this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
buildFilePath, false, this->GetMakefileEncoding());
- if (!this->BuildFileStream) {
+ if (!(*this->BuildFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -780,19 +749,20 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
*this->BuildFileStream
<< "# This file contains all the build statements describing the\n"
<< "# compilation DAG.\n\n";
+
+ return true;
}
void cmGlobalNinjaGenerator::CloseBuildFileStream()
{
if (this->BuildFileStream) {
- delete this->BuildFileStream;
- this->BuildFileStream = nullptr;
+ this->BuildFileStream.reset();
} else {
cmSystemTools::Error("Build file stream was not open.");
}
}
-void cmGlobalNinjaGenerator::OpenRulesFileStream()
+bool cmGlobalNinjaGenerator::OpenRulesFileStream()
{
// Compute Ninja's build file path.
std::string rulesFilePath =
@@ -802,12 +772,12 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
// Get a stream where to generate things.
if (!this->RulesFileStream) {
- this->RulesFileStream = new cmGeneratedFileStream(
+ this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>(
rulesFilePath, false, this->GetMakefileEncoding());
- if (!this->RulesFileStream) {
+ if (!(*this->RulesFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -822,13 +792,13 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
<< "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
;
/* clang-format on */
+ return true;
}
void cmGlobalNinjaGenerator::CloseRulesFileStream()
{
if (this->RulesFileStream) {
- delete this->RulesFileStream;
- this->RulesFileStream = nullptr;
+ this->RulesFileStream.reset();
} else {
cmSystemTools::Error("Rules file stream was not open.");
}
@@ -871,6 +841,11 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath(
.first->second;
}
+void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName)
+{
+ this->AdditionalCleanFiles.emplace(std::move(fileName));
+}
+
void cmGlobalNinjaGenerator::AddCXXCompileCommand(
const std::string& commandLine, const std::string& sourceFile)
{
@@ -885,7 +860,8 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
}
// Get a stream where to generate things.
- this->CompileCommandsStream = new cmGeneratedFileStream(buildFilePath);
+ this->CompileCommandsStream =
+ cm::make_unique<cmGeneratedFileStream>(buildFilePath);
*this->CompileCommandsStream << "[";
} else {
*this->CompileCommandsStream << "," << std::endl;
@@ -899,11 +875,11 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
/* clang-format off */
*this->CompileCommandsStream << "\n{\n"
- << " \"directory\": \""
+ << R"( "directory": ")"
<< cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
- << " \"command\": \""
+ << R"( "command": ")"
<< cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
- << " \"file\": \""
+ << R"( "file": ")"
<< cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
<< "}";
/* clang-format on */
@@ -913,8 +889,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
{
if (this->CompileCommandsStream) {
*this->CompileCommandsStream << "\n]";
- delete this->CompileCommandsStream;
- this->CompileCommandsStream = nullptr;
+ this->CompileCommandsStream.reset();
}
}
@@ -944,7 +919,8 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
std::back_inserter(orderOnlyDeps));
WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
"Assume dependencies for generated source file.",
- /*depfile*/ "", /*uses_terminal*/ false,
+ /*depfile*/ "", /*job_pool*/ "",
+ /*uses_terminal*/ false,
/*restat*/ true, cmNinjaDeps(1, asd.first),
cmNinjaDeps(), orderOnlyDeps);
}
@@ -1010,8 +986,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
{
if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// These depend only on other CMake-provided targets, e.g. "all".
- std::set<BT<std::string>> const& utils = target->GetUtilities();
- for (BT<std::string> const& util : utils) {
+ for (BT<std::string> const& util : target->GetUtilities()) {
std::string d =
target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" +
util.Value;
@@ -1019,15 +994,15 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
}
} else {
cmNinjaDeps outs;
- cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& targetDep : targetDeps) {
+ for (cmTargetDepend const& targetDep :
+ this->GetTargetDirectDepends(target)) {
if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
this->AppendTargetOutputs(targetDep, outs, depends);
}
std::sort(outs.begin(), outs.end());
- outputs.insert(outputs.end(), outs.begin(), outs.end());
+ cmAppend(outputs, outs);
}
}
@@ -1036,8 +1011,7 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
{
cmNinjaOuts outs;
this->AppendTargetDependsClosure(target, outs, true);
-
- outputs.insert(outputs.end(), outs.begin(), outs.end());
+ cmAppend(outputs, outs);
}
void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
@@ -1054,10 +1028,9 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
// relevant for filling the cache entries properly isolated and a global
// result set that is relevant for the result of the top level call to
// AppendTargetDependsClosure.
- auto const& targetDeps = this->GetTargetDirectDepends(target);
cmNinjaOuts this_outs; // this will be the new cache entry
- for (auto const& dep_target : targetDeps) {
+ for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -1107,6 +1080,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
cmGlobalNinjaGenerator::WriteDivider(os);
os << "# Target aliases.\n\n";
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
for (auto const& ta : TargetAliases) {
// Don't write ambiguous aliases.
if (!ta.second) {
@@ -1119,10 +1094,13 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
continue;
}
- cmNinjaDeps deps;
- this->AppendTargetOutputs(ta.second, deps);
-
- this->WritePhonyBuild(os, "", cmNinjaDeps(1, ta.first), deps);
+ // Outputs
+ build.Outputs[0] = ta.first;
+ // Explicit depdendencies
+ build.ExplicitDeps.clear();
+ this->AppendTargetOutputs(ta.second, build.ExplicitDeps);
+ // Write
+ this->WriteBuild(os, build);
}
}
@@ -1131,13 +1109,22 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
cmGlobalNinjaGenerator::WriteDivider(os);
os << "# Folder targets.\n\n";
+ std::string const& rootBinaryDir =
+ this->LocalGenerators[0]->GetBinaryDirectory();
+
std::map<std::string, cmNinjaDeps> targetsPerFolder;
for (cmLocalGenerator const* lg : this->LocalGenerators) {
- const std::string currentBinaryFolder(
+ std::string const& currentBinaryFolder(
lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
+
+ // Do not generate a rule for the root binary dir.
+ if (currentBinaryFolder == rootBinaryDir) {
+ continue;
+ }
+
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
- targetsPerFolder[currentBinaryFolder] = cmNinjaDeps();
+ cmNinjaDeps& folderTargets = targetsPerFolder[currentBinaryFolder];
for (auto gt : lg->GetGeneratorTargets()) {
cmStateEnums::TargetType const type = gt->GetType();
if ((type == cmStateEnums::EXECUTABLE ||
@@ -1147,39 +1134,34 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
type == cmStateEnums::OBJECT_LIBRARY ||
type == cmStateEnums::UTILITY) &&
!gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
- targetsPerFolder[currentBinaryFolder].push_back(gt->GetName());
+ folderTargets.push_back(gt->GetName());
}
}
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
- std::vector<cmStateSnapshot> const& children =
- lg->GetStateSnapshot().GetChildren();
- for (cmStateSnapshot const& state : children) {
- std::string const currentBinaryDir =
+ for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
+ std::string const& currentBinaryDir =
state.GetDirectory().GetCurrentBinary();
-
- targetsPerFolder[currentBinaryFolder].push_back(
+ folderTargets.push_back(
this->ConvertToNinjaPath(currentBinaryDir + "/all"));
}
}
- std::string const rootBinaryDir =
- this->LocalGenerators[0]->GetBinaryDirectory();
- for (auto const& it : targetsPerFolder) {
- cmGlobalNinjaGenerator::WriteDivider(os);
- std::string const& currentBinaryDir = it.first;
+ if (!targetsPerFolder.empty()) {
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
+ for (auto& it : targetsPerFolder) {
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ std::string const& currentBinaryDir = it.first;
- // Do not generate a rule for the root binary dir.
- if (rootBinaryDir.length() >= currentBinaryDir.length()) {
- continue;
+ // Setup target
+ build.Comment = "Folder: " + currentBinaryDir;
+ build.Outputs[0] = this->ConvertToNinjaPath(currentBinaryDir + "/all");
+ build.ExplicitDeps = std::move(it.second);
+ // Write target
+ this->WriteBuild(os, build);
}
-
- std::string const comment = "Folder: " + currentBinaryDir;
- cmNinjaDeps output(1);
- output.push_back(this->ConvertToNinjaPath(currentBinaryDir + "/all"));
-
- this->WritePhonyBuild(os, comment, output, it.second);
}
}
@@ -1216,26 +1198,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
for (cmLocalGenerator* lg : this->LocalGenerators) {
// get the vector of files created by this makefile and convert them
// to ninja paths, which are all relative in respect to the build directory
- const std::vector<std::string>& files =
- lg->GetMakefile()->GetOutputFiles();
- for (std::string const& file : files) {
+ for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(file));
}
if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
// get list files which are implicit dependencies as well and will be
// phony for rebuild manifest
- std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles();
- for (std::string const& j : lf) {
+ for (std::string const& j : lg->GetMakefile()->GetListFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(j));
}
}
- std::vector<cmGeneratorExpressionEvaluationFile*> const& ef =
- lg->GetMakefile()->GetEvaluationFiles();
- for (cmGeneratorExpressionEvaluationFile* li : ef) {
+ for (cmGeneratorExpressionEvaluationFile* li :
+ lg->GetMakefile()->GetEvaluationFiles()) {
// get all the files created by generator expressions and convert them
// to ninja paths
- std::vector<std::string> evaluationFiles = li->GetFiles();
- for (std::string const& evaluationFile : evaluationFiles) {
+ for (std::string const& evaluationFile : li->GetFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(evaluationFile));
}
}
@@ -1265,23 +1242,26 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
knownDependencies.begin(), knownDependencies.end(),
std::back_inserter(unknownExplicitDepends));
- std::string const rootBuildDirectory =
- this->GetCMakeInstance()->GetHomeOutputDirectory();
- bool const inSourceBuild =
- (rootBuildDirectory == this->GetCMakeInstance()->GetHomeDirectory());
std::vector<std::string> warnExplicitDepends;
- for (std::string const& i : unknownExplicitDepends) {
- // verify the file is in the build directory
- std::string const absDepPath =
- cmSystemTools::CollapseFullPath(i, rootBuildDirectory.c_str());
- bool const inBuildDir =
- cmSystemTools::IsSubDirectory(absDepPath, rootBuildDirectory);
- if (inBuildDir) {
- cmNinjaDeps deps(1, i);
- this->WritePhonyBuild(os, "", deps, cmNinjaDeps());
- if (this->PolicyCMP0058 == cmPolicies::WARN && !inSourceBuild &&
- warnExplicitDepends.size() < 10) {
- warnExplicitDepends.push_back(i);
+ if (!unknownExplicitDepends.empty()) {
+ cmake* cmk = this->GetCMakeInstance();
+ std::string const& buildRoot = cmk->GetHomeOutputDirectory();
+ bool const inSource = (buildRoot == cmk->GetHomeDirectory());
+ bool const warn = (!inSource && (this->PolicyCMP0058 == cmPolicies::WARN));
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
+ for (std::string const& ued : unknownExplicitDepends) {
+ // verify the file is in the build directory
+ std::string const absDepPath =
+ cmSystemTools::CollapseFullPath(ued, buildRoot);
+ if (cmSystemTools::IsSubDirectory(absDepPath, buildRoot)) {
+ // Generate phony build statement
+ build.Outputs[0] = ued;
+ this->WriteBuild(os, build);
+ // Add to warning on demand
+ if (warn && warnExplicitDepends.size() < 10) {
+ warnExplicitDepends.push_back(ued);
+ }
}
}
}
@@ -1322,14 +1302,14 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
{
- cmNinjaDeps outputs;
- outputs.push_back(this->TargetAll);
-
- this->WritePhonyBuild(os, "The main all target.", outputs,
- this->AllDependencies);
+ cmNinjaBuild build("phony");
+ build.Comment = "The main all target.";
+ build.Outputs.push_back(this->TargetAll);
+ build.ExplicitDeps = this->AllDependencies;
+ this->WriteBuild(os, build);
if (!this->HasOutputPathPrefix()) {
- cmGlobalNinjaGenerator::WriteDefault(os, outputs,
+ cmGlobalNinjaGenerator::WriteDefault(os, build.Outputs,
"Make the all target the default.");
}
}
@@ -1341,84 +1321,74 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
}
cmLocalGenerator* lg = this->LocalGenerators[0];
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -S"
- << lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
- cmOutputConverter::SHELL)
- << " -B"
- << lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
- cmOutputConverter::SHELL);
- WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd.str(),
- "Re-running CMake...", "Rule for re-running cmake.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
-
- cmNinjaDeps implicitDeps;
- cmNinjaDeps explicitDeps;
+ {
+ cmNinjaRule rule("RERUN_CMAKE");
+ rule.Command = CMakeCmd();
+ rule.Command += " -S";
+ rule.Command += lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL);
+ rule.Command += " -B";
+ rule.Command += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL);
+ rule.Description = "Re-running CMake...";
+ rule.Comment = "Rule for re-running cmake.";
+ rule.Generator = true;
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild reBuild("RERUN_CMAKE");
+ reBuild.Comment = "Re-run CMake if any of its inputs changed.";
+ reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- std::vector<std::string> const& lf =
- localGen->GetMakefile()->GetListFiles();
- for (std::string const& fi : lf) {
- implicitDeps.push_back(this->ConvertToNinjaPath(fi));
+ for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) {
+ reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi));
}
}
- implicitDeps.push_back(this->CMakeCacheFile);
+ reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
- cmNinjaVars variables;
// Use 'console' pool to get non buffered output of the CMake re-run call
// Available since Ninja 1.5
if (SupportsConsolePool()) {
- variables["pool"] = "console";
+ reBuild.Variables["pool"] = "console";
}
cmake* cm = this->GetCMakeInstance();
if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
- std::ostringstream verify_cmd;
- verify_cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -P "
- << lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
- cmOutputConverter::SHELL);
-
- WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", verify_cmd.str(),
- "Re-checking globbed directories...",
- "Rule for re-checking globbed directories.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
-
- std::string verifyForce = cm->GetGlobVerifyScript() + "_force";
- cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce));
-
- this->WritePhonyBuild(os, "Phony target to force glob verification run.",
- verifyForceDeps, cmNinjaDeps());
-
- variables["restat"] = "1";
+ {
+ cmNinjaRule rule("VERIFY_GLOBS");
+ rule.Command = CMakeCmd();
+ rule.Command += " -P ";
+ rule.Command += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL);
+ rule.Description = "Re-checking globbed directories...";
+ rule.Comment = "Rule for re-checking globbed directories.";
+ rule.Generator = true;
+ this->WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild phonyBuild("phony");
+ phonyBuild.Comment = "Phony target to force glob verification run.";
+ phonyBuild.Outputs.push_back(cm->GetGlobVerifyScript() + "_force");
+ this->WriteBuild(os, phonyBuild);
+
+ reBuild.Variables["restat"] = "1";
std::string const verifyScriptFile =
this->NinjaOutputPath(cm->GetGlobVerifyScript());
std::string const verifyStampFile =
this->NinjaOutputPath(cm->GetGlobVerifyStamp());
- this->WriteBuild(os,
- "Re-run CMake to check if globbed directories changed.",
- "VERIFY_GLOBS",
- /*outputs=*/cmNinjaDeps(1, verifyStampFile),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/verifyForceDeps,
- /*orderOnlyDeps=*/cmNinjaDeps(), variables);
-
- variables.erase("restat");
- implicitDeps.push_back(verifyScriptFile);
- explicitDeps.push_back(verifyStampFile);
+ {
+ cmNinjaBuild vgBuild("VERIFY_GLOBS");
+ vgBuild.Comment =
+ "Re-run CMake to check if globbed directories changed.";
+ vgBuild.Outputs.push_back(verifyStampFile);
+ vgBuild.ImplicitDeps = phonyBuild.Outputs;
+ vgBuild.Variables = reBuild.Variables;
+ this->WriteBuild(os, vgBuild);
+ }
+ reBuild.Variables.erase("restat");
+ reBuild.ImplicitDeps.push_back(verifyScriptFile);
+ reBuild.ExplicitDeps.push_back(verifyStampFile);
} else if (!this->SupportsManifestRestat() &&
cm->DoWriteGlobVerifyTarget()) {
std::ostringstream msg;
@@ -1436,31 +1406,36 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
msg.str());
}
- std::sort(implicitDeps.begin(), implicitDeps.end());
- implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
- implicitDeps.end());
+ std::sort(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end());
+ reBuild.ImplicitDeps.erase(
+ std::unique(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end()),
+ reBuild.ImplicitDeps.end());
- std::string const ninjaBuildFile = this->NinjaOutputPath(NINJA_BUILD_FILE);
- this->WriteBuild(os, "Re-run CMake if any of its inputs changed.",
- "RERUN_CMAKE",
- /*outputs=*/cmNinjaDeps(1, ninjaBuildFile),
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps,
- /*orderOnlyDeps=*/cmNinjaDeps(), variables);
+ this->WriteBuild(os, reBuild);
- cmNinjaDeps missingInputs;
- std::set_difference(std::make_move_iterator(implicitDeps.begin()),
- std::make_move_iterator(implicitDeps.end()),
- CustomCommandOutputs.begin(), CustomCommandOutputs.end(),
- std::back_inserter(missingInputs));
+ {
+ cmNinjaBuild build("phony");
+ 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(),
+ std::back_inserter(build.Outputs));
+ this->WriteBuild(os, build);
+ }
+}
- this->WritePhonyBuild(os, "A missing CMake input file is not an error.",
- missingInputs, cmNinjaDeps());
+std::string cmGlobalNinjaGenerator::CMakeCmd() const
+{
+ cmLocalGenerator* lgen = this->LocalGenerators.at(0);
+ return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::SHELL);
}
-std::string cmGlobalNinjaGenerator::ninjaCmd() const
+std::string cmGlobalNinjaGenerator::NinjaCmd() const
{
cmLocalGenerator* lgen = this->LocalGenerators[0];
- if (lgen) {
+ if (lgen != nullptr) {
return lgen->ConvertToOutputFormat(this->NinjaCommand,
cmOutputConverter::SHELL);
}
@@ -1487,44 +1462,106 @@ bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const
return this->NinjaSupportsMultilineDepfile;
}
+bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
+{
+ cmLocalGenerator* lgr = this->LocalGenerators.at(0);
+ std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake";
+ std::string cleanScriptAbs = lgr->GetBinaryDirectory();
+ cleanScriptAbs += '/';
+ cleanScriptAbs += cleanScriptRel;
+
+ // Check if there are additional files to clean
+ if (this->AdditionalCleanFiles.empty()) {
+ // Remove cmake clean script file if it exists
+ cmSystemTools::RemoveFile(cleanScriptAbs);
+ return false;
+ }
+
+ // Write cmake clean script file
+ {
+ cmGeneratedFileStream fout(cleanScriptAbs);
+ if (!fout) {
+ return false;
+ }
+ fout << "# Additional clean files\n\n";
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& acf : this->AdditionalCleanFiles) {
+ fout << " "
+ << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf))
+ << '\n';
+ }
+ fout << ")\n";
+ }
+ // Register clean script file
+ lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs);
+
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN_ADDITIONAL");
+ rule.Command = CMakeCmd();
+ rule.Command += " -P ";
+ rule.Command += lgr->ConvertToOutputFormat(
+ this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL);
+ rule.Description = "Cleaning additional files...";
+ rule.Comment = "Rule for cleaning additional files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN_ADDITIONAL");
+ build.Comment = "Clean additional files.";
+ build.Outputs.push_back(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+ WriteBuild(os, build);
+ }
+ // Return success
+ return true;
+}
+
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean",
- "Cleaning all built files...",
- "Rule for cleaning all built files.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/false);
- WriteBuild(os, "Clean all the built files.", "CLEAN",
- /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("clean")),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/cmNinjaDeps(),
- /*orderOnlyDeps=*/cmNinjaDeps(),
- /*variables=*/cmNinjaVars());
+ // -- Additional clean target
+ bool additionalFiles = WriteTargetCleanAdditional(os);
+
+ // -- Default clean target
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN");
+ rule.Command = NinjaCmd() + " -t clean";
+ rule.Description = "Cleaning all built files...";
+ rule.Comment = "Rule for cleaning all built files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN");
+ build.Comment = "Clean all the built files.";
+ build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName()));
+ if (additionalFiles) {
+ build.ExplicitDeps.push_back(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+ }
+ WriteBuild(os, build);
+ }
}
void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "HELP", ninjaCmd() + " -t targets",
- "All primary targets available:",
- "Rule for printing all primary targets available.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/false);
- WriteBuild(os, "Print all primary targets available.", "HELP",
- /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/cmNinjaDeps(),
- /*orderOnlyDeps=*/cmNinjaDeps(),
- /*variables=*/cmNinjaVars());
+ {
+ cmNinjaRule rule("HELP");
+ rule.Command = NinjaCmd() + " -t targets";
+ rule.Description = "All primary targets available:";
+ rule.Comment = "Rule for printing all primary targets available.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+ {
+ cmNinjaBuild build("HELP");
+ build.Comment = "Print all primary targets available.";
+ build.Outputs.push_back(this->NinjaOutputPath("help"));
+ WriteBuild(os, build);
+ }
}
void cmGlobalNinjaGenerator::InitOutputPathPrefix()
@@ -1573,12 +1610,13 @@ Compilation of source files within a target is split into the following steps:
command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
cmake -E cmake_ninja_depends \
--tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
- --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE
+ --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
+ --lang=Fortran
- build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
+ build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90
OBJ_FILE = src.f90.o
- DEP_FILE = src.f90-pp.f90.d
- DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi
+ DEP_FILE = src.f90.o.d
+ DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi
The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
and generates the ninja depfile for preprocessor dependencies. It also
@@ -1592,9 +1630,9 @@ Compilation of source files within a target is split into the following steps:
rule Fortran_DYNDEP
command = cmake -E cmake_ninja_dyndep \
- --tdi=FortranDependInfo.json --dd=$out $in
+ --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
- build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
+ build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi
The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
sources in the target and the ``FortranModules.json`` files from targets
@@ -1632,6 +1670,19 @@ 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);
+
int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
std::vector<std::string>::const_iterator argEnd)
{
@@ -1640,8 +1691,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
std::string arg_dep;
std::string arg_obj;
std::string arg_ddi;
- for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
- std::string const& arg = *a;
+ std::string arg_lang;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
if (cmHasLiteralPrefix(arg, "--tdi=")) {
arg_tdi = arg.substr(6);
} else if (cmHasLiteralPrefix(arg, "--pp=")) {
@@ -1652,9 +1703,10 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
arg_obj = arg.substr(6);
} else if (cmHasLiteralPrefix(arg, "--ddi=")) {
arg_ddi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
} else {
- cmSystemTools::Error("-E cmake_ninja_depends unknown argument: ",
- arg.c_str());
+ cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg);
return 1;
}
}
@@ -1678,7 +1730,61 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
return 1;
}
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
+ return 1;
+ }
+
+ std::unique_ptr<cmSourceInfo> info;
+ if (arg_lang == "Fortran") {
+ info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
+ } else {
+ cmSystemTools::Error("-E cmake_ninja_depends does not understand the " +
+ arg_lang + " language");
+ return 1;
+ }
+
+ if (!info) {
+ // The error message is already expected to have been output.
+ return 1;
+ }
+
+ {
+ cmGeneratedFileStream depfile(arg_dep);
+ depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+ for (std::string const& include : info->Includes) {
+ depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
+ }
+ 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) {
+ cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi);
+ return 1;
+ }
+ return 0;
+}
+std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+ std::string const& arg_tdi, std::string const& arg_pp)
+{
cmFortranCompiler fc;
std::vector<std::string> includes;
{
@@ -1688,10 +1794,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(tdif, tdio, false)) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to parse ",
- arg_tdi.c_str(),
- reader.getFormattedErrorMessages().c_str());
- return 1;
+ cmSystemTools::Error("-E cmake_ninja_depends failed to parse " +
+ arg_tdi + reader.getFormattedErrorMessages());
+ return nullptr;
}
}
@@ -1712,54 +1817,26 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
fc.SModExt = tdi_submodule_ext.asString();
}
- cmFortranSourceInfo info;
+ cmFortranSourceInfo finfo;
std::set<std::string> defines;
- cmFortranParser parser(fc, includes, defines, info);
+ cmFortranParser parser(fc, includes, defines, finfo);
if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to open ",
- arg_pp.c_str());
- return 1;
+ cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp);
+ return nullptr;
}
if (cmFortran_yyparse(parser.Scanner) != 0) {
// Failed to parse the file.
- return 1;
- }
-
- {
- cmGeneratedFileStream depfile(arg_dep);
- depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
- for (std::string const& include : info.Includes) {
- depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
- }
- depfile << "\n";
+ return nullptr;
}
- 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) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to write ",
- arg_ddi.c_str());
- return 1;
- }
- return 0;
+ auto info = cm::make_unique<cmSourceInfo>();
+ info->Provides = finfo.Provides;
+ info->Requires = finfo.Requires;
+ info->Includes = finfo.Includes;
+ return info;
}
-struct cmFortranObjectInfo
+struct cmDyndepObjectInfo
{
std::string Object;
std::vector<std::string> Provides;
@@ -1771,7 +1848,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
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::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang)
{
// Setup path conversions.
{
@@ -1788,7 +1866,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
this->LocalGenerators.push_back(lgd.release());
}
- std::vector<cmFortranObjectInfo> objects;
+ std::vector<cmDyndepObjectInfo> objects;
for (std::string const& arg_ddi : arg_ddis) {
// Load the ddi file and compute the module file paths it provides.
Json::Value ddio;
@@ -1796,13 +1874,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(ddif, ddio, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- arg_ddi.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_ddi +
+ reader.getFormattedErrorMessages());
return false;
}
- cmFortranObjectInfo info;
+ cmDyndepObjectInfo info;
info.Object = ddi["object"].asString();
Json::Value const& ddi_provides = ddi["provides"];
if (ddi_provides.isArray()) {
@@ -1824,14 +1901,15 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
// Populate the module map with those provided by linked targets first.
for (std::string const& linked_target_dir : linked_target_dirs) {
- std::string const ltmn = linked_target_dir + "/FortranModules.json";
+ std::string const ltmn =
+ linked_target_dir + "/" + arg_lang + "Modules.json";
Json::Value ltm;
cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (ltmf && !reader.parse(ltmf, ltm, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- linked_target_dir.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " +
+ linked_target_dir +
+ reader.getFormattedErrorMessages());
return false;
}
if (ltm.isObject()) {
@@ -1845,7 +1923,7 @@ 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 (cmFortranObjectInfo const& object : objects) {
+ for (cmDyndepObjectInfo const& object : objects) {
for (std::string const& p : object.Provides) {
std::string const mod = module_dir + p;
mod_files[p] = mod;
@@ -1856,38 +1934,35 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmGeneratedFileStream ddf(arg_dd);
ddf << "ninja_dyndep_version = 1.0\n";
- for (cmFortranObjectInfo const& object : objects) {
- std::string const ddComment;
- std::string const ddRule = "dyndep";
- cmNinjaDeps ddOutputs;
- cmNinjaDeps ddImplicitOuts;
- cmNinjaDeps ddExplicitDeps;
- cmNinjaDeps ddImplicitDeps;
- cmNinjaDeps ddOrderOnlyDeps;
- cmNinjaVars ddVars;
-
- ddOutputs.push_back(object.Object);
- for (std::string const& p : object.Provides) {
- ddImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p]));
- }
- for (std::string const& r : object.Requires) {
- std::map<std::string, std::string>::iterator m = mod_files.find(r);
- if (m != mod_files.end()) {
- ddImplicitDeps.push_back(this->ConvertToNinjaPath(m->second));
+ {
+ cmNinjaBuild build("dyndep");
+ build.Outputs.emplace_back("");
+ for (cmDyndepObjectInfo const& object : objects) {
+ build.Outputs[0] = object.Object;
+ build.ImplicitOuts.clear();
+ for (std::string const& p : object.Provides) {
+ build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p]));
+ }
+ build.ImplicitDeps.clear();
+ for (std::string const& r : object.Requires) {
+ auto mit = mod_files.find(r);
+ if (mit != mod_files.end()) {
+ build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second));
+ }
+ }
+ build.Variables.clear();
+ if (!object.Provides.empty()) {
+ build.Variables.emplace("restat", "1");
}
- }
- if (!object.Provides.empty()) {
- ddVars["restat"] = "1";
- }
- this->WriteBuild(ddf, ddComment, ddRule, ddOutputs, ddImplicitOuts,
- ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ this->WriteBuild(ddf, build);
+ }
}
// Store the map of modules provided by this target in a file for
// use by dependents that reference this target in linked-target-dirs.
std::string const target_mods_file =
- cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json";
+ cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json";
cmGeneratedFileStream tmf(target_mods_file);
tmf << tm;
@@ -1901,19 +1976,21 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::HandleResponseFile(argBeg, argEnd);
std::string arg_dd;
+ std::string arg_lang;
std::string arg_tdi;
std::vector<std::string> arg_ddis;
for (std::string const& arg : arg_full) {
if (cmHasLiteralPrefix(arg, "--tdi=")) {
arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
} else if (cmHasLiteralPrefix(arg, "--dd=")) {
arg_dd = arg.substr(5);
} else if (!cmHasLiteralPrefix(arg, "--") &&
cmHasLiteralSuffix(arg, ".ddi")) {
arg_ddis.push_back(arg);
} else {
- cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: ",
- arg.c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: " + arg);
return 1;
}
}
@@ -1921,6 +1998,10 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
return 1;
}
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang=");
+ return 1;
+ }
if (arg_dd.empty()) {
cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
return 1;
@@ -1932,9 +2013,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(tdif, tdio, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- arg_tdi.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_tdi +
+ reader.getFormattedErrorMessages());
return 1;
}
}
@@ -1944,7 +2024,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
std::string const dir_top_bld = tdi["dir-top-bld"].asString();
std::string const dir_top_src = tdi["dir-top-src"].asString();
std::string module_dir = tdi["module-dir"].asString();
- if (!module_dir.empty()) {
+ if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
module_dir += "/";
}
std::vector<std::string> linked_target_dirs;
@@ -1962,8 +2042,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
if (!ggd ||
!ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
- arg_dd, arg_ddis, module_dir,
- linked_target_dirs)) {
+ arg_dd, arg_ddis, module_dir, linked_target_dirs,
+ arg_lang)) {
return 1;
}
return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 226b73dfd..15dd4044e 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -7,12 +7,15 @@
#include <iosfwd>
#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include <vector>
+#include "cmGeneratedFileStream.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -21,7 +24,6 @@
#include "cm_codecvt.hxx"
class cmCustomCommand;
-class cmGeneratedFileStream;
class cmGeneratorTarget;
class cmLinkLineComputer;
class cmLocalGenerator;
@@ -41,8 +43,6 @@ struct cmDocumentationEntry;
* it is handle by Ninja's -v option.
* - We don't care about computing any progress status since Ninja manages
* it itself.
- * - We don't care about generating a clean target since Ninja already have
- * a clean tool.
* - We generate one build.ninja and one rules.ninja per project.
* - We try to minimize the number of generated rules: one per target and
* language.
@@ -101,54 +101,27 @@ public:
bool IsIPOSupported() const override { return true; }
/**
- * Write a build statement to @a os with the @a comment using
- * the @a rule the list of @a outputs files and inputs.
- * It also writes the variables bound to this build statement.
+ * Write a build statement @a build to @a os.
* @warning no escaping of any kind is done here.
*/
- void WriteBuild(std::ostream& os, const std::string& comment,
- const std::string& rule, const cmNinjaDeps& outputs,
- const cmNinjaDeps& implicitOuts,
- const cmNinjaDeps& explicitDeps,
- const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps,
- const cmNinjaVars& variables,
- const std::string& rspfile = std::string(),
+ void WriteBuild(std::ostream& os, cmNinjaBuild const& build,
int cmdLineLimit = 0, bool* usedResponseFile = nullptr);
- /**
- * Helper to write a build statement with the special 'phony' rule.
- */
- void WritePhonyBuild(std::ostream& os, const std::string& comment,
- const cmNinjaDeps& outputs,
- const cmNinjaDeps& explicitDeps,
- const cmNinjaDeps& implicitDeps = cmNinjaDeps(),
- const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(),
- const cmNinjaVars& variables = cmNinjaVars());
-
- void WriteCustomCommandBuild(const std::string& command,
- const std::string& description,
- const std::string& comment,
- const std::string& depfile, bool uses_terminal,
- bool restat, const cmNinjaDeps& outputs,
- const cmNinjaDeps& deps = cmNinjaDeps(),
- const cmNinjaDeps& orderOnly = cmNinjaDeps());
- void WriteMacOSXContentBuild(const std::string& input,
- const std::string& output);
+ void WriteCustomCommandBuild(
+ const std::string& command, const std::string& description,
+ const std::string& comment, const std::string& depfile,
+ const std::string& pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs,
+ const cmNinjaDeps& explicitDeps = cmNinjaDeps(),
+ const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
+
+ void WriteMacOSXContentBuild(std::string input, std::string output);
/**
- * Write a rule statement named @a name to @a os with the @a comment,
- * the mandatory @a command, the @a depfile and the @a description.
- * It also writes the variables bound to this rule statement.
+ * Write a rule statement to @a os.
* @warning no escaping of any kind is done here.
*/
- static void WriteRule(std::ostream& os, const std::string& name,
- const std::string& command,
- const std::string& description,
- const std::string& comment, const std::string& depfile,
- const std::string& deptype, const std::string& rspfile,
- const std::string& rspcontent,
- const std::string& restat, bool generator);
+ static void WriteRule(std::ostream& os, cmNinjaRule const& rule);
/**
* Write a variable named @a name to @a os with value @a value and an
@@ -200,15 +173,12 @@ public:
void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile* mf, bool optional) override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
// Setup target names
const char* GetAllTargetName() const override { return "all"; }
@@ -236,12 +206,12 @@ public:
cmGeneratedFileStream* GetBuildFileStream() const
{
- return this->BuildFileStream;
+ return this->BuildFileStream.get();
}
cmGeneratedFileStream* GetRulesFileStream() const
{
- return this->RulesFileStream;
+ return this->RulesFileStream.get();
}
std::string const& ConvertToNinjaPath(const std::string& path) const;
@@ -260,6 +230,13 @@ public:
};
MapToNinjaPathImpl MapToNinjaPath() { return MapToNinjaPathImpl(this); }
+ // -- Additional clean files
+ void AddAdditionalCleanFile(std::string fileName);
+ const char* GetAdditionalCleanTargetName() const
+ {
+ return "CMakeFiles/clean.additional";
+ }
+
void AddCXXCompileCommand(const std::string& commandLine,
const std::string& sourceFile);
@@ -268,11 +245,7 @@ public:
* Call WriteRule() behind the scene but perform some check before like:
* - Do not add twice the same rule.
*/
- void AddRule(const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator);
+ void AddRule(cmNinjaRule const& rule);
bool HasRule(const std::string& name);
@@ -329,9 +302,9 @@ public:
return LocalGenerators;
}
- bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target)
+ bool IsExcluded(cmGeneratorTarget* target)
{
- return cmGlobalGenerator::IsExcluded(root, target);
+ return cmGlobalGenerator::IsExcluded(target);
}
int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
@@ -365,7 +338,8 @@ public:
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::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang);
protected:
void Generate() override;
@@ -380,12 +354,12 @@ private:
cmMakefile* mf) const override;
bool CheckFortran(cmMakefile* mf) const;
- void OpenBuildFileStream();
+ bool OpenBuildFileStream();
void CloseBuildFileStream();
void CloseCompileCommandsStream();
- void OpenRulesFileStream();
+ bool OpenRulesFileStream();
void CloseRulesFileStream();
/// Write the common disclaimer text at the top of each build file.
@@ -400,6 +374,7 @@ private:
void WriteBuiltinTargets(std::ostream& os);
void WriteTargetAll(std::ostream& os);
void WriteTargetRebuildManifest(std::ostream& os);
+ bool WriteTargetCleanAdditional(std::ostream& os);
void WriteTargetClean(std::ostream& os);
void WriteTargetHelp(std::ostream& os);
@@ -407,25 +382,22 @@ private:
cmGeneratorTarget const* target,
std::set<cmGeneratorTarget const*>& depends);
- std::string ninjaCmd() const;
+ std::string CMakeCmd() const;
+ std::string NinjaCmd() const;
/// The file containing the build statement. (the relationship of the
/// compilation DAG).
- cmGeneratedFileStream* BuildFileStream;
+ std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
/// The file containing the rule statements. (The action attached to each
/// edge of the compilation DAG).
- cmGeneratedFileStream* RulesFileStream;
- cmGeneratedFileStream* CompileCommandsStream;
-
- /// The type used to store the set of rules added to the generated build
- /// system.
- typedef std::set<std::string> RulesSetType;
+ std::unique_ptr<cmGeneratedFileStream> RulesFileStream;
+ std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream;
/// The set of rules added to the generated build system.
- RulesSetType Rules;
+ std::unordered_set<std::string> Rules;
/// Length of rule command, used by rsp file evaluation
- std::map<std::string, int> RuleCmdLength;
+ std::unordered_map<std::string, int> RuleCmdLength;
/// The set of dependencies to add to the "all" target.
cmNinjaDeps AllDependencies;
@@ -475,6 +447,7 @@ private:
std::string OutputPathPrefix;
std::string TargetAll;
std::string CMakeCacheFile;
+ std::set<std::string> AdditionalCleanFiles;
};
#endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index f1a128a83..aa584add7 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -57,7 +57,7 @@ void cmGlobalUnixMakefileGenerator3::EnableLanguage(
}
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -169,7 +169,7 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
{
if (this->CommandDatabase == nullptr) {
std::string commandDatabaseName =
- std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) +
+ this->GetCMakeInstance()->GetHomeOutputDirectory() +
"/compile_commands.json";
this->CommandDatabase = new cmGeneratedFileStream(commandDatabaseName);
*this->CommandDatabase << "[" << std::endl;
@@ -177,13 +177,13 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
*this->CommandDatabase << "," << std::endl;
}
*this->CommandDatabase << "{" << std::endl
- << " \"directory\": \""
+ << R"( "directory": ")"
<< cmGlobalGenerator::EscapeJSON(workingDirectory)
<< "\"," << std::endl
- << " \"command\": \""
+ << R"( "command": ")"
<< cmGlobalGenerator::EscapeJSON(compileCommand)
<< "\"," << std::endl
- << " \"file\": \""
+ << R"( "file": ")"
<< cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
<< std::endl
<< "}";
@@ -232,28 +232,16 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
depends.push_back(this->EmptyRuleHackDepends);
}
- // Write and empty all:
- lg->WriteMakeRule(makefileStream, "The main recursive all target", "all",
- depends, no_commands, true);
-
- // Write an empty preinstall:
- lg->WriteMakeRule(makefileStream, "The main recursive preinstall target",
- "preinstall", depends, no_commands, true);
-
- // Write an empty clean:
- lg->WriteMakeRule(makefileStream, "The main recursive clean target", "clean",
- depends, no_commands, true);
-
// Write out the "special" stuff
lg->WriteSpecialTargetsTop(makefileStream);
- // write the target convenience rules
+ // Write the target convenience rules
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
- this->WriteConvenienceRules2(makefileStream, lg);
+ this->WriteConvenienceRules2(
+ makefileStream, static_cast<cmLocalUnixMakefileGenerator3*>(localGen));
}
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+ // Write special bottom targets
lg->WriteSpecialTargetsBottom(makefileStream);
}
@@ -294,11 +282,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
// for each cmMakefile get its list of dependencies
std::vector<std::string> lfiles;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
-
// Get the list of files contributing to this generation step.
- lfiles.insert(lfiles.end(), lg->GetMakefile()->GetListFiles().begin(),
- lg->GetMakefile()->GetListFiles().end());
+ cmAppend(lfiles, localGen->GetMakefile()->GetListFiles());
}
cmake* cm = this->GetCMakeInstance();
@@ -354,9 +339,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
{
cmakefileStream << "# Byproducts of CMake generate step:\n"
<< "set(CMAKE_MAKEFILE_PRODUCTS\n";
- const std::vector<std::string>& outfiles =
- lg->GetMakefile()->GetOutputFiles();
- for (std::string const& outfile : outfiles) {
+ for (std::string const& outfile : lg->GetMakefile()->GetOutputFiles()) {
cmakefileStream << " \""
<< lg->MaybeConvertToRelativePath(binDir, outfile)
<< "\"\n";
@@ -392,8 +375,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
for (cmLocalGenerator* lGenerator : lGenerators) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerator);
// for all of out targets
- const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : tgts) {
+ for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
if ((tgt->GetType() == cmStateEnums::EXECUTABLE) ||
(tgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
(tgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
@@ -413,18 +395,18 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg,
- const char* pass, bool check_all, bool check_relink)
+ const char* pass, bool check_all, bool check_relink,
+ std::vector<std::string> const& commands)
{
// Get the relative path to the subdirectory from the top.
std::string makeTarget = lg->GetCurrentBinaryDirectory();
- makeTarget += "/";
+ makeTarget += '/';
makeTarget += pass;
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
std::vector<std::string> depends;
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
int type = gtarget->GetType();
if ((type == cmStateEnums::EXECUTABLE) ||
(type == cmStateEnums::STATIC_LIBRARY) ||
@@ -446,10 +428,9 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
- std::vector<cmStateSnapshot> children = lg->GetStateSnapshot().GetChildren();
- for (cmStateSnapshot const& c : children) {
+ for (cmStateSnapshot const& c : lg->GetStateSnapshot().GetChildren()) {
std::string subdir = c.GetDirectory().GetCurrentBinary();
- subdir += "/";
+ subdir += '/';
subdir += pass;
depends.push_back(std::move(subdir));
}
@@ -461,44 +442,58 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
}
// Write the rule.
- std::string doc = "Convenience name for \"";
- doc += pass;
- doc += "\" pass in the directory.";
- std::vector<std::string> no_commands;
- lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
- no_commands, true);
+ std::string doc;
+ if (lg->IsRootMakefile()) {
+ doc = "The main recursive \"";
+ doc += pass;
+ doc += "\" target.";
+ } else {
+ doc = "Recursive \"";
+ doc += pass;
+ doc += "\" directory target.";
+ }
+ lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends, commands,
+ true);
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
{
- // Only subdirectories need these rules.
- if (lg->IsRootMakefile()) {
- return;
- }
-
// Begin the directory-level rules section.
- std::string dir =
- cmSystemTools::ConvertToOutputPath(lg->MaybeConvertToRelativePath(
- lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory()));
- lg->WriteDivider(ruleFileStream);
- ruleFileStream << "# Directory level rules for directory " << dir << "\n\n";
+ {
+ std::string dir =
+ cmSystemTools::ConvertToOutputPath(lg->MaybeConvertToRelativePath(
+ lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory()));
+ lg->WriteDivider(ruleFileStream);
+ if (lg->IsRootMakefile()) {
+ ruleFileStream << "# Directory level rules for the build root directory";
+ } else {
+ ruleFileStream << "# Directory level rules for directory " << dir;
+ }
+ ruleFileStream << "\n\n";
+ }
// Write directory-level rules for "all".
this->WriteDirectoryRule2(ruleFileStream, lg, "all", true, false);
// Write directory-level rules for "clean".
- this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false);
+ {
+ std::vector<std::string> cmds;
+ lg->AppendDirectoryCleanCommand(cmds);
+ this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false, cmds);
+ }
// Write directory-level rules for "preinstall".
this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
}
-void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& /*projectName*/, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& /*config*/, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& /*config*/,
+ bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::unique_ptr<cmMakefile> mfu;
cmMakefile* mf;
@@ -515,34 +510,38 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
mf = mfu.get();
}
+ GeneratedMakeCommand makeCommand;
+
// Make it possible to set verbosity also from command line
if (verbose) {
- makeCommand.add(cmSystemTools::GetCMakeCommand());
- makeCommand.add("-E");
- makeCommand.add("env");
- makeCommand.add("VERBOSE=1");
+ makeCommand.Add(cmSystemTools::GetCMakeCommand());
+ makeCommand.Add("-E");
+ makeCommand.Add("env");
+ makeCommand.Add("VERBOSE=1");
}
- makeCommand.add(this->SelectMakeProgram(makeProgram));
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-j");
+ makeCommand.Add("-j");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
- if (!targetName.empty()) {
- std::string tname = targetName;
- if (fast) {
- tname += "/fast";
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (auto tname : targetNames) {
+ if (!tname.empty()) {
+ if (fast) {
+ tname += "/fast";
+ }
+ tname =
+ mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
+ mf->GetState()->GetBinaryDirectory(), tname);
+ cmSystemTools::ConvertToOutputSlashes(tname);
+ makeCommand.Add(std::move(tname));
}
- tname =
- mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
- mf->GetState()->GetBinaryDirectory(), tname);
- cmSystemTools::ConvertToOutputSlashes(tname);
- makeCommand.add(std::move(tname));
}
+ return { std::move(makeCommand) };
}
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
@@ -561,8 +560,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
cmLocalUnixMakefileGenerator3* lg =
static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
// Don't emit the same rule twice (e.g. two targets with the same
// simple name)
int type = gtarget->GetType();
@@ -646,8 +644,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
}
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
int type = gtarget->GetType();
std::string name = gtarget->GetName();
if (!name.empty() &&
@@ -687,9 +684,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
{
std::ostringstream progressArg;
const char* sep = "";
- std::vector<unsigned long> const& progFiles =
- this->ProgressMap[gtarget].Marks;
- for (unsigned long progFile : progFiles) {
+ for (unsigned long progFile : this->ProgressMap[gtarget].Marks) {
progressArg << sep << progFile;
sep = ",";
}
@@ -712,15 +707,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
localName, depends, commands, true);
- // add the all/all dependency
- if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
- depends.clear();
- depends.push_back(localName);
- commands.clear();
- lg->WriteMakeRule(ruleFileStream, "Include target in all.", "all",
- depends, commands, true);
- }
-
// Write the rule.
commands.clear();
@@ -777,7 +763,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
"Pre-install relink rule for target.", localName,
depends, commands, true);
- if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
+ if (!this->IsExcluded(gtarget)) {
depends.clear();
depends.push_back(localName);
commands.clear();
@@ -797,9 +783,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
makeTargetName, depends, commands, true);
commands.clear();
- depends.push_back(makeTargetName);
- lg->WriteMakeRule(ruleFileStream, "clean rule for target.", "clean",
- depends, commands, true);
}
}
}
@@ -811,8 +794,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
this->DirectoryTargetsMap.clear();
// Loop over all targets in all local generators.
for (cmLocalGenerator* lg : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gt : targets) {
+ for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) {
cmLocalGenerator* tlg = gt->GetLocalGenerator();
if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -835,8 +817,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
// Add dependencies of the included target. An excluded
// target may still be included if it is a dependency of a
// non-excluded target.
- TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(gt);
- for (cmTargetDepend const& tgtdep : tgtdeps) {
+ for (cmTargetDepend const& tgtdep : this->GetTargetDirectDepends(gt)) {
targetSet.insert(tgtdep);
}
}
@@ -850,8 +831,7 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
size_t count = 0;
if (emitted.insert(target).second) {
count = this->ProgressMap[target].Marks.size();
- TargetDependSet const& depends = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& depend : depends) {
+ for (cmTargetDepend const& depend : this->GetTargetDirectDepends(target)) {
if (depend->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -866,9 +846,8 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
{
size_t count = 0;
std::set<cmGeneratorTarget const*> emitted;
- std::set<cmGeneratorTarget const*> const& targets =
- this->DirectoryTargetsMap[lg->GetStateSnapshot()];
- for (cmGeneratorTarget const* target : targets) {
+ for (cmGeneratorTarget const* target :
+ this->DirectoryTargetsMap[lg->GetStateSnapshot()]) {
count += this->CountProgressMarksInTarget(target, emitted);
}
return count;
@@ -907,8 +886,7 @@ void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
std::vector<std::string>& depends, cmGeneratorTarget* target)
{
- TargetDependSet const& depends_set = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& i : depends_set) {
+ for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) {
// Create the target-level dependency.
cmGeneratorTarget const* dep = i;
if (dep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -950,9 +928,7 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
// the targets
if (lg2 == lg || lg->IsRootMakefile()) {
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets =
- lg2->GetGeneratorTargets();
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : lg2->GetGeneratorTargets()) {
cmStateEnums::TargetType type = target->GetType();
if ((type == cmStateEnums::EXECUTABLE) ||
(type == cmStateEnums::STATIC_LIBRARY) ||
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 8a80acc05..287472c81 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -67,7 +67,7 @@ public:
cmGlobalUnixMakefileGenerator3>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalUnixMakefileGenerator3::GetActualName();
@@ -127,15 +127,12 @@ public:
std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
// change the build command for speed
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/** Record per-target progress information. */
void RecordTargetProgress(cmMakefileTargetGenerator* tg);
@@ -168,7 +165,8 @@ protected:
void WriteDirectoryRule2(std::ostream& ruleFileStream,
cmLocalUnixMakefileGenerator3* lg, const char* pass,
- bool check_all, bool check_relink);
+ bool check_all, bool check_relink,
+ std::vector<std::string> const& commands = {});
void WriteDirectoryRules2(std::ostream& ruleFileStream,
cmLocalUnixMakefileGenerator3* lg);
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index d8b2e892c..55374a48e 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -509,7 +509,7 @@ std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
return "";
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -784,11 +784,11 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
if (this->GetSystemName() == "WindowsPhone") {
cmXMLElement(epg, "ApplicationType").Content("Windows Phone");
cmXMLElement(epg, "ApplicationTypeRevision")
- .Content(this->GetSystemVersion());
+ .Content(this->GetApplicationTypeRevision());
} else if (this->GetSystemName() == "WindowsStore") {
cmXMLElement(epg, "ApplicationType").Content("Windows Store");
cmXMLElement(epg, "ApplicationTypeRevision")
- .Content(this->GetSystemVersion());
+ .Content(this->GetApplicationTypeRevision());
}
if (!this->WindowsTargetPlatformVersion.empty()) {
cmXMLElement(epg, "WindowsTargetPlatformVersion")
@@ -878,12 +878,14 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
return true;
}
-void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio10Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
+ std::vector<GeneratedMakeCommand> makeCommands;
// Select the caller- or user-preferred make program, else MSBuild.
std::string makeProgramSelected =
this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
@@ -895,7 +897,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
makeProgramLower.find("vcexpress") != std::string::npos);
// Workaround to convince VCExpress.exe to produce output.
- makeCommand.RequiresOutputForward =
+ const bool requiresOutputForward =
(makeProgramLower.find("vcexpress") != std::string::npos);
// MSBuild is preferred (and required for VS Express), but if the .sln has
@@ -913,10 +915,11 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
if (parser.ParseFile(slnFile, slnData,
cmVisualStudioSlnParser::DataGroupProjects)) {
std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
- for (std::vector<cmSlnProjectEntry>::const_iterator i =
- slnProjects.cbegin();
- !useDevEnv && i != slnProjects.cend(); ++i) {
- std::string proj = i->GetRelativePath();
+ for (cmSlnProjectEntry const& project : slnProjects) {
+ if (useDevEnv) {
+ break;
+ }
+ std::string proj = project.GetRelativePath();
if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
useDevEnv = true;
}
@@ -925,62 +928,71 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
}
if (useDevEnv) {
// Use devenv to build solutions containing Intel Fortran projects.
- cmGlobalVisualStudio7Generator::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, jobs, verbose, makeOptions);
- return;
- }
+ return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, makeOptions);
+ }
+
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
+ }
+ for (const auto& tname : realTargetNames) {
+ // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
+ // /target:ALL_BUILD
+ // /m
+ if (tname.empty()) {
+ continue;
+ }
- makeCommand.add(makeProgramSelected);
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
- std::string realTarget = targetName;
- // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
- // /m
- if (realTarget.empty()) {
- realTarget = "ALL_BUILD";
- }
- if (realTarget == "clean") {
- makeCommand.add(std::string(projectName) + ".sln");
- makeCommand.add("/t:Clean");
- } else {
- std::string targetProject(realTarget);
- targetProject += ".vcxproj";
- if (targetProject.find('/') == std::string::npos) {
- // it might be in a subdir
- if (cmSlnProjectEntry const* proj =
- slnData.GetProjectByName(realTarget)) {
- targetProject = proj->GetRelativePath();
- cmSystemTools::ConvertToUnixSlashes(targetProject);
+ if (tname == "clean") {
+ makeCommand.Add(std::string(projectName) + ".sln");
+ makeCommand.Add("/t:Clean");
+ } else {
+ std::string targetProject(tname);
+ targetProject += ".vcxproj";
+ if (targetProject.find('/') == std::string::npos) {
+ // it might be in a subdir
+ if (cmSlnProjectEntry const* proj = slnData.GetProjectByName(tname)) {
+ targetProject = proj->GetRelativePath();
+ cmSystemTools::ConvertToUnixSlashes(targetProject);
+ }
}
+ makeCommand.Add(std::move(targetProject));
}
- makeCommand.add(std::move(targetProject));
- }
- std::string configArg = "/p:Configuration=";
- if (!config.empty()) {
- configArg += config;
- } else {
- configArg += "Debug";
- }
- makeCommand.add(configArg);
- makeCommand.add(std::string("/p:Platform=") + this->GetPlatformName());
- makeCommand.add(std::string("/p:VisualStudioVersion=") +
- this->GetIDEVersion());
-
- if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("/m");
+ std::string configArg = "/p:Configuration=";
+ if (!config.empty()) {
+ configArg += config;
} else {
- makeCommand.add(std::string("/m:") + std::to_string(jobs));
+ configArg += "Debug";
+ }
+ makeCommand.Add(configArg);
+ makeCommand.Add(std::string("/p:Platform=") + this->GetPlatformName());
+ makeCommand.Add(std::string("/p:VisualStudioVersion=") +
+ this->GetIDEVersion());
+
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add("/m");
+ } else {
+ makeCommand.Add(std::string("/m:") + std::to_string(jobs));
+ }
+ // Having msbuild.exe and cl.exe using multiple jobs is discouraged
+ makeCommand.Add("/p:CL_MPCount=1");
}
- // Having msbuild.exe and cl.exe using multiple jobs is discouraged
- makeCommand.add("/p:CL_MPCount=1");
- }
-
- // Respect the verbosity: 'n' normal will show build commands
- // 'm' minimal only the build step's title
- makeCommand.add(std::string("/v:") + ((verbose) ? "n" : "m"));
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ // Respect the verbosity: 'n' normal will show build commands
+ // 'm' minimal only the build step's title
+ makeCommand.Add(std::string("/v:") + ((verbose) ? "n" : "m"));
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
}
bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
@@ -1005,7 +1017,7 @@ bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
winSDK_7_1)) {
std::ostringstream m;
m << "Found Windows SDK v7.1: " << winSDK_7_1;
- mf->DisplayStatus(m.str().c_str(), -1);
+ mf->DisplayStatus(m.str(), -1);
this->DefaultPlatformToolset = "Windows7.1SDK";
return true;
} else {
@@ -1100,6 +1112,15 @@ std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
return version;
}
+std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
+{
+ // Return the first two '.'-separated components of the Windows version.
+ std::string::size_type end1 = this->SystemVersion.find('.');
+ std::string::size_type end2 =
+ end1 == std::string::npos ? end1 : this->SystemVersion.find('.', end1 + 1);
+ return this->SystemVersion.substr(0, end2);
+}
+
static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
{
if (entry.isMember(field)) {
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 3ef7abfd0..1d30cd6b3 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -22,17 +22,14 @@ public:
bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
-
- ///! create the correct local generator
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ //! create the correct local generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -113,6 +110,9 @@ public:
static std::string GetInstalledNsightTegraVersion();
+ /** Return the first two components of CMAKE_SYSTEM_VERSION. */
+ std::string GetApplicationTypeRevision() const;
+
cmIDEFlagTable const* GetClFlagTable() const;
cmIDEFlagTable const* GetCSharpFlagTable() const;
cmIDEFlagTable const* GetRcFlagTable() const;
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 4eb78ba9c..4b74ef1b2 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -252,15 +252,10 @@ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs()
return ret;
}
-bool cmGlobalVisualStudio11Generator::NeedsDeploy(
- cmStateEnums::TargetType type) const
+bool cmGlobalVisualStudio11Generator::TargetSystemSupportsDeployment() const
{
- if ((type == cmStateEnums::EXECUTABLE ||
- type == cmStateEnums::SHARED_LIBRARY) &&
- (this->SystemIsWindowsPhone || this->SystemIsWindowsStore)) {
- return true;
- }
- return cmGlobalVisualStudio10Generator::NeedsDeploy(type);
+ return this->SystemIsWindowsPhone || this->SystemIsWindowsStore ||
+ cmGlobalVisualStudio10Generator::TargetSystemSupportsDeployment();
}
bool cmGlobalVisualStudio11Generator::IsWindowsDesktopToolsetInstalled() const
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index 8b4c8b739..f8cce1898 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -45,8 +45,8 @@ protected:
bool UseFolderProperty() const override;
static std::set<std::string> GetInstalledWindowsCESDKs();
- /** Return true if the configuration needs to be deployed */
- bool NeedsDeploy(cmStateEnums::TargetType type) const override;
+ /** Return true if target system supports debugging deployment. */
+ bool TargetSystemSupportsDeployment() const override;
private:
class Factory;
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 20258678a..6509b5616 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -179,7 +179,7 @@ void cmGlobalVisualStudio14Generator::SetWindowsTargetPlatformVersion(
std::ostringstream e;
e << "Selecting Windows SDK version " << this->WindowsTargetPlatformVersion
<< " to target Windows " << this->SystemVersion << ".";
- mf->DisplayStatus(e.str().c_str(), -1);
+ mf->DisplayStatus(e.str(), -1);
}
mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
this->WindowsTargetPlatformVersion.c_str());
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index d138c1e78..8764ee439 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -45,7 +45,6 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
cmake* cm, std::string const& platformInGeneratorName)
: cmGlobalVisualStudioGenerator(cm, platformInGeneratorName)
{
- this->IntelProjectVersion = 0;
this->DevEnvCommandInitialized = false;
this->MasmEnabled = false;
this->NasmEnabled = false;
@@ -54,21 +53,20 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator()
{
- free(this->IntelProjectVersion);
}
// Package GUID of Intel Visual Fortran plugin to VS IDE
#define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}"
-const char* cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
+const std::string& cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
{
- if (!this->IntelProjectVersion) {
+ if (this->IntelProjectVersion.empty()) {
// Compute the version of the Intel plugin to the VS IDE.
// If the key does not exist then use a default guess.
std::string intelVersion;
std::string vskey = this->GetRegistryBase();
vskey += "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion";
- cmSystemTools::ReadRegistryValue(vskey.c_str(), intelVersion,
+ cmSystemTools::ReadRegistryValue(vskey, intelVersion,
cmSystemTools::KeyWOW64_32);
unsigned int intelVersionNumber = ~0u;
sscanf(intelVersion.c_str(), "%u", &intelVersionNumber);
@@ -81,7 +79,7 @@ const char* cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
} else {
// Version <= 9: use ProductVersion from registry.
}
- this->IntelProjectVersion = strdup(intelVersion.c_str());
+ this->IntelProjectVersion = intelVersion;
}
return this->IntelProjectVersion;
}
@@ -190,11 +188,14 @@ const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
}
return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
}
-void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& config, bool /*fast*/,
- int /*jobs*/, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int /*jobs*/, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
// Select the caller- or user-preferred make program, else devenv.
std::string makeProgramSelected =
@@ -210,27 +211,42 @@ void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
}
// Workaround to convince VCExpress.exe to produce output.
- makeCommand.RequiresOutputForward =
+ const bool requiresOutputForward =
(makeProgramLower.find("vcexpress") != std::string::npos);
+ std::vector<GeneratedMakeCommand> makeCommands;
- makeCommand.add(makeProgramSelected);
-
- makeCommand.add(std::string(projectName) + ".sln");
- std::string realTarget = targetName;
- bool clean = false;
- if (realTarget == "clean") {
- clean = true;
- realTarget = "ALL_BUILD";
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
}
-
- makeCommand.add((clean ? "/clean" : "/build"));
- makeCommand.add((config.empty() ? "Debug" : config));
- makeCommand.add("/project");
- makeCommand.add((realTarget.empty() ? "ALL_BUILD" : realTarget));
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ for (const auto& tname : realTargetNames) {
+ std::string realTarget;
+ if (!tname.empty()) {
+ realTarget = tname;
+ } else {
+ continue;
+ }
+ bool clean = false;
+ if (realTarget == "clean") {
+ clean = true;
+ realTarget = "ALL_BUILD";
+ }
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
+ makeCommand.Add(projectName + ".sln");
+ makeCommand.Add((clean ? "/clean" : "/build"));
+ makeCommand.Add((config.empty() ? "Debug" : config));
+ makeCommand.Add("/project");
+ makeCommand.Add(realTarget);
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -252,7 +268,7 @@ bool cmGlobalVisualStudio7Generator::SetSystemName(std::string const& s,
cmMakefile* mf)
{
mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
- this->GetIntelProjectVersion());
+ this->GetIntelProjectVersion().c_str());
return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
}
@@ -597,7 +613,7 @@ std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name)
{
std::string const& guidStoreName = name + "_GUID_CMAKE";
if (const char* storedGUID =
- this->CMakeInstance->GetCacheDefinition(guidStoreName.c_str())) {
+ this->CMakeInstance->GetCacheDefinition(guidStoreName)) {
return std::string(storedGUID);
}
// Compute a GUID that is deterministic but unique to the build tree.
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 3f1c1732d..f004afb9c 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -20,7 +20,7 @@ class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator
public:
~cmGlobalVisualStudio7Generator();
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -52,22 +52,19 @@ public:
* Try running cmake and building a file. This is used for dynamically
* loaded commands, not as part of the usual build process.
*/
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/**
* Generate the DSW workspace file.
*/
virtual void OutputSLNFile();
- ///! Lookup a stored GUID or compute one deterministically.
+ //! Lookup a stored GUID or compute one deterministically.
std::string GetGUID(std::string const& name);
/** Append the subdirectory for the given configuration. */
@@ -76,7 +73,7 @@ public:
const std::string& suffix,
std::string& dir) override;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
const char* GetCMakeCFGIntDir() const override
{
return "$(ConfigurationName)";
@@ -89,7 +86,7 @@ public:
return false;
}
- const char* GetIntelProjectVersion();
+ const std::string& GetIntelProjectVersion();
bool FindMakeProgram(cmMakefile* mf) override;
@@ -166,7 +163,7 @@ protected:
bool NasmEnabled;
private:
- char* IntelProjectVersion;
+ std::string IntelProjectVersion;
std::string DevEnvCommand;
bool DevEnvCommandInitialized;
std::string GetVSMakeProgram() override { return this->GetDevEnvCommand(); }
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index f6db018ea..85ddc85b5 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -141,10 +141,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
// Collect the input files used to generate all targets in this
// project.
std::vector<std::string> listFiles;
- for (unsigned int j = 0; j < generators.size(); ++j) {
- cmMakefile* lmf = generators[j]->GetMakefile();
- listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(),
- lmf->GetListFiles().end());
+ for (cmLocalGenerator* gen : generators) {
+ cmAppend(listFiles, gen->GetMakefile()->GetListFiles());
}
// Add a custom prebuild target to run the VerifyGlobs script.
@@ -188,8 +186,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
commandLine.push_back("--check-stamp-list");
commandLine.push_back(stampList.c_str());
commandLine.push_back("--vs-solution-file");
- std::string const sln = std::string(lg->GetBinaryDirectory()) + "/" +
- lg->GetProjectName() + ".sln";
+ std::string const sln =
+ lg->GetBinaryDirectory() + "/" + lg->GetProjectName() + ".sln";
commandLine.push_back(sln);
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
@@ -205,7 +203,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
"Checking Build System", no_working_directory, true, false)) {
gt->AddSource(file->GetFullPath());
} else {
- cmSystemTools::Error("Error adding rule for ", stamps[0].c_str());
+ cmSystemTools::Error("Error adding rule for " + stamps[0]);
}
}
@@ -273,7 +271,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
: this->GetPlatformName())
<< "\n";
}
- if (this->NeedsDeploy(target.GetType())) {
+ if (this->NeedsDeploy(target, dstConfig)) {
fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
<< ".Deploy.0 = " << dstConfig << "|"
<< (!platformMapping.empty() ? platformMapping
@@ -284,11 +282,32 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
}
bool cmGlobalVisualStudio8Generator::NeedsDeploy(
- cmStateEnums::TargetType type) const
+ cmGeneratorTarget const& target, const char* config) const
{
- bool needsDeploy =
- (type == cmStateEnums::EXECUTABLE || type == cmStateEnums::SHARED_LIBRARY);
- return this->TargetsWindowsCE() && needsDeploy;
+ cmStateEnums::TargetType type = target.GetType();
+ bool noDeploy = DeployInhibited(target, config);
+ return !noDeploy &&
+ (type == cmStateEnums::EXECUTABLE ||
+ type == cmStateEnums::SHARED_LIBRARY) &&
+ this->TargetSystemSupportsDeployment();
+}
+
+bool cmGlobalVisualStudio8Generator::DeployInhibited(
+ cmGeneratorTarget const& target, const char* config) const
+{
+ bool rVal = false;
+ if (const char* propStr = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propStr);
+ std::string prop = cge->Evaluate(target.LocalGenerator, config);
+ rVal = cmSystemTools::IsOn(prop);
+ }
+ return rVal;
+}
+
+bool cmGlobalVisualStudio8Generator::TargetSystemSupportsDeployment() const
+{
+ return this->TargetsWindowsCE();
}
bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 8719bf3bb..352bc3c2b 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -13,7 +13,7 @@
class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator
{
public:
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override { return this->Name; }
/** Get the name of the main stamp list file. */
@@ -54,7 +54,15 @@ protected:
bool AddCheckTarget();
/** Return true if the configuration needs to be deployed */
- virtual bool NeedsDeploy(cmStateEnums::TargetType type) const;
+ virtual bool NeedsDeploy(cmGeneratorTarget const& target,
+ const char* config) const;
+
+ /** Returns true if deployment has been disabled in cmake file. */
+ bool DeployInhibited(cmGeneratorTarget const& target,
+ const char* config) const;
+
+ /** Returns true if the target system support debugging deployment. */
+ virtual bool TargetSystemSupportsDeployment() const;
static cmIDEFlagTable const* GetExtraFlagTableVS8();
void WriteSolutionConfigurations(
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index cc5a88004..cd0355f6f 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmAlgorithms.h"
#include "cmCallVisualStudioMacro.h"
+#include "cmCustomCommand.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmLocalVisualStudioGenerator.h"
@@ -202,14 +203,12 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
// Now make all targets depend on the ALL_BUILD target
for (cmLocalGenerator const* i : gen) {
- std::vector<cmGeneratorTarget*> const& targets =
- i->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : targets) {
+ for (cmGeneratorTarget* tgt : i->GetGeneratorTargets()) {
if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
tgt->IsImported()) {
continue;
}
- if (!this->IsExcluded(gen[0], tgt)) {
+ if (!this->IsExcluded(tgt)) {
allBuild->AddUtility(tgt->GetName());
}
}
@@ -317,17 +316,7 @@ void cmGlobalVisualStudioGenerator::CallVisualStudioMacro(
std::vector<std::string> filenames;
this->GetFilesReplacedDuringGenerate(filenames);
if (!filenames.empty()) {
- // Convert vector to semi-colon delimited string of filenames:
- std::string projects;
- std::vector<std::string>::iterator it = filenames.begin();
- if (it != filenames.end()) {
- projects = *it;
- ++it;
- }
- for (; it != filenames.end(); ++it) {
- projects += ";";
- projects += *it;
- }
+ std::string projects = cmJoin(filenames, ";");
cmCallVisualStudioMacro::CallMacro(
topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
this->GetCMakeInstance()->GetDebugOutput());
@@ -367,7 +356,7 @@ void cmGlobalVisualStudioGenerator::FillLinkClosure(
cmGlobalVisualStudioGenerator::TargetSet const&
cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target)
{
- TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
+ auto i = this->TargetLinkClosure.find(target);
if (i == this->TargetLinkClosure.end()) {
TargetSetMap::value_type entry(target, TargetSet());
i = this->TargetLinkClosure.insert(entry).first;
@@ -401,11 +390,8 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
return false;
}
for (auto const& it : this->ProjectMap) {
- std::vector<cmLocalGenerator*> const& gen = it.second;
- for (const cmLocalGenerator* i : gen) {
- std::vector<cmGeneratorTarget*> const& targets =
- i->GetGeneratorTargets();
- for (cmGeneratorTarget* ti : targets) {
+ for (const cmLocalGenerator* i : it.second) {
+ for (cmGeneratorTarget* ti : i->GetGeneratorTargets()) {
this->ComputeVSTargetDepends(ti);
}
}
@@ -457,8 +443,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
std::set<cmGeneratorTarget const*> linkDepends;
if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
for (cmTargetDepend const& di : depends) {
- cmTargetDepend dep = di;
- if (dep.IsLink()) {
+ if (di.IsLink()) {
this->FollowLinkDepends(di, linkDepends);
}
}
@@ -467,8 +452,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
// Collect explicit util dependencies (add_dependencies).
std::set<cmGeneratorTarget const*> utilDepends;
for (cmTargetDepend const& di : depends) {
- cmTargetDepend dep = di;
- if (dep.IsUtil()) {
+ if (di.IsUtil()) {
this->FollowLinkDepends(di, utilDepends);
}
}
@@ -512,7 +496,7 @@ bool cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf)
std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
cmGeneratorTarget const* target)
{
- UtilityDependsMap::iterator i = this->UtilityDepends.find(target);
+ auto i = this->UtilityDepends.find(target);
if (i == this->UtilityDepends.end()) {
std::string name = this->WriteUtilityDepend(target);
UtilityDependsMap::value_type entry(target, name);
@@ -930,7 +914,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
cmdl.push_back(objs_file);
cmGeneratedFileStream fout(objs_file.c_str());
if (!fout) {
- cmSystemTools::Error("could not open ", objs_file.c_str());
+ cmSystemTools::Error("could not open " + objs_file);
return;
}
@@ -938,11 +922,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
std::vector<std::string> objs;
for (cmSourceFile const* it : objectSources) {
// Find the object file name corresponding to this source file.
- std::map<cmSourceFile const*, std::string>::const_iterator map_it =
- mapping.find(it);
// It must exist because we populated the mapping just above.
- assert(!map_it->second.empty());
- std::string objFile = obj_dir + map_it->second;
+ const auto& v = mapping[it];
+ assert(!v.empty());
+ std::string objFile = obj_dir + v;
objs.push_back(objFile);
}
std::vector<cmSourceFile const*> externalObjectSources;
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index f52abd0dc..2ba1affde 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -211,8 +211,8 @@ class cmGlobalVisualStudioVersionedGenerator::Factory16
: public cmGlobalGeneratorFactory
{
public:
- virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
- cmake* cm) const
+ cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const override
{
std::string genName;
const char* p = cmVS16GenName(name, genName);
@@ -226,7 +226,7 @@ public:
return 0;
}
- virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ void GetDocumentation(cmDocumentationEntry& entry) const override
{
entry.Name = std::string(vs16generatorName);
entry.Brief = "Generates Visual Studio 2019 project files. "
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index c02c4711a..8a2738431 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -3,6 +3,7 @@
#include "cmGlobalWatcomWMakeGenerator.h"
#include "cmDocumentationEntry.h"
+#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmake.h"
@@ -50,15 +51,16 @@ void cmGlobalWatcomWMakeGenerator::GetDocumentation(
entry.Brief = "Generates Watcom WMake makefiles.";
}
-void cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index 6680b193f..3ca5e7d86 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -29,7 +29,7 @@ public:
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalWatcomWMakeGenerator::GetActualName();
@@ -50,15 +50,12 @@ public:
bool AllowDeleteOnError() const override { return false; }
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index dc63ce66b..7c2bcd386 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
@@ -201,7 +202,7 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
}
}
}
- if (!versionFile.empty() && cmSystemTools::FileExists(versionFile.c_str())) {
+ if (!versionFile.empty() && cmSystemTools::FileExists(versionFile)) {
parser.ParseFile(versionFile.c_str());
} else if (cmSystemTools::FileExists(
"/Applications/Xcode.app/Contents/version.plist")) {
@@ -217,7 +218,7 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]);
unsigned int version_number = 10 * v[0] + v[1];
- if (version_number < 30) {
+ if (version_number < 50) {
cm->IssueMessage(MessageType::FATAL_ERROR,
"Xcode " + version_string + " not supported.");
return nullptr;
@@ -256,15 +257,11 @@ std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
{
- if (this->XcodeVersion >= 40) {
- std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
- if (makeProgram.empty()) {
- makeProgram = "xcodebuild";
- }
- return makeProgram;
+ std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
+ if (makeProgram.empty()) {
+ makeProgram = "xcodebuild";
}
- // Use cmakexbuild wrapper to suppress environment dump from output.
- return cmSystemTools::GetCMakeCommand() + "xbuild";
+ return makeProgram;
}
bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
@@ -338,49 +335,61 @@ bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
return ret;
}
-void cmGlobalXCodeGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& config, bool /*fast*/,
- int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalXCodeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
+ GeneratedMakeCommand makeCommand;
// now build the test
- makeCommand.add(
+ makeCommand.Add(
this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
if (!projectName.empty()) {
- makeCommand.add("-project");
+ makeCommand.Add("-project");
std::string projectArg = projectName;
projectArg += ".xcode";
projectArg += "proj";
- makeCommand.add(projectArg);
+ makeCommand.Add(projectArg);
}
-
- bool clean = false;
- std::string realTarget = targetName;
- if (realTarget == "clean") {
- clean = true;
- realTarget = "ALL_BUILD";
+ if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+ targetNames.end()) {
+ makeCommand.Add("clean");
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ makeCommand.Add("build");
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add("-target", tname);
+ }
+ }
+ }
}
- makeCommand.add((clean ? "clean" : "build"));
- makeCommand.add("-target", (realTarget.empty() ? "ALL_BUILD" : realTarget));
- makeCommand.add("-configuration", (config.empty() ? "Debug" : config));
+ makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-jobs");
+ makeCommand.Add("-jobs");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
if (this->XcodeVersion >= 70) {
- makeCommand.add("-hideShellScriptEnvironment");
+ makeCommand.Add("-hideShellScriptEnvironment");
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ return { std::move(makeCommand) };
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf)
{
return new cmLocalXCodeGenerator(this, mf);
@@ -470,7 +479,7 @@ void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
this->CurrentXCodeHackMakefile = root->GetCurrentBinaryDirectory();
this->CurrentXCodeHackMakefile += "/CMakeScripts";
- cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
+ cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile);
this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
}
@@ -550,12 +559,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
// run the depend check makefile as a post build rule
// this will make sure that when the next target is built
// things are up-to-date
- if (target->GetType() == cmStateEnums::OBJECT_LIBRARY ||
- (this->XcodeVersion < 50 &&
- (target->GetType() == cmStateEnums::EXECUTABLE ||
- target->GetType() == cmStateEnums::STATIC_LIBRARY ||
- target->GetType() == cmStateEnums::SHARED_LIBRARY ||
- target->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
makeHelper.back() = // fill placeholder
this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
cmCustomCommandLines commandLines;
@@ -564,10 +568,10 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
gen->GetMakefile()->AddCustomCommandToTarget(
target->GetName(), no_byproducts, no_depends, commandLines,
cmTarget::POST_BUILD, "Depend check for xcode", dir.c_str(), true,
- false, "", false, cmMakefile::AcceptObjectLibraryCommands);
+ false, "", "", false, cmMakefile::AcceptObjectLibraryCommands);
}
- if (!this->IsExcluded(gens[0], target)) {
+ if (!this->IsExcluded(target)) {
allbuild->AddUtility(target->GetName());
}
}
@@ -579,8 +583,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
{
std::vector<std::string> lfiles;
for (auto gen : gens) {
- std::vector<std::string> const& lf = gen->GetMakefile()->GetListFiles();
- lfiles.insert(lfiles.end(), lf.begin(), lf.end());
+ cmAppend(lfiles, gen->GetMakefile()->GetListFiles());
}
// sort the array
@@ -596,7 +599,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
this->CurrentReRunCMakeMakefile = root->GetCurrentBinaryDirectory();
this->CurrentReRunCMakeMakefile += "/CMakeScripts";
- cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
+ cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile);
this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
cmGeneratedFileStream makefileStream(this->CurrentReRunCMakeMakefile);
makefileStream.SetCopyIfDifferent(true);
@@ -1019,11 +1022,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
this->CreateString(fileType));
// Store the file path relative to the top of the source tree.
- std::string path = this->RelativeToSource(fullpath.c_str());
+ std::string path = this->RelativeToSource(fullpath);
std::string name = cmSystemTools::GetFilenameName(path);
const char* sourceTree =
- (cmSystemTools::FileIsFullPath(path.c_str()) ? "<absolute>"
- : "SOURCE_ROOT");
+ cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
fileRef->AddAttribute("name", this->CreateString(name));
fileRef->AddAttribute("path", this->CreateString(path));
fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
@@ -1190,23 +1192,6 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
}
}
- if (this->XcodeVersion < 50) {
- // Add object library contents as external objects. (Equivalent to
- // the externalObjFiles above, except each one is not a cmSourceFile
- // within the target.)
- std::vector<cmSourceFile const*> objs;
- gtgt->GetExternalObjects(objs, "");
- for (auto sourceFile : objs) {
- if (sourceFile->GetObjectLibrary().empty()) {
- continue;
- }
- std::string const& obj = sourceFile->GetFullPath();
- cmXCodeObject* xsf =
- this->CreateXCodeSourceFileFromPath(obj, gtgt, "", nullptr);
- externalObjFiles.push_back(xsf);
- }
- }
-
// some build phases only apply to bundles and/or frameworks
bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
@@ -1601,7 +1586,7 @@ std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp,
std::string::size_type offset = 0;
- while (regex.find(flags.c_str() + offset)) {
+ while (regex.find(&flags[offset])) {
const std::string::size_type startPos = offset + regex.start(matchIndex);
const std::string::size_type endPos = offset + regex.end(matchIndex);
const std::string::size_type size = endPos - startPos;
@@ -1654,7 +1639,7 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
{
std::string dir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
dir += "/CMakeScripts";
- cmSystemTools::MakeDirectory(dir.c_str());
+ cmSystemTools::MakeDirectory(dir);
std::string makefile = dir;
makefile += "/";
makefile += target->GetName();
@@ -1713,7 +1698,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
} else {
std::ostringstream str;
str << "_buildpart_" << count++;
- tname[&ccg.GetCC()] = std::string(target->GetName()) + str.str();
+ tname[&ccg.GetCC()] = target->GetName() + str.str();
makefileStream << "\\\n\t" << tname[&ccg.GetCC()];
}
}
@@ -1820,6 +1805,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
configName);
+ if (gtgt->IsIPOEnabled(lang, configName)) {
+ this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
// Add shared-library flags if needed.
this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
configName);
@@ -1833,8 +1822,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
std::string llang = gtgt->GetLinkerLanguage(configName);
if (binary && llang.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- gtgt->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ gtgt->GetName());
return;
}
std::string const& langForPreprocessor = llang;
@@ -2009,7 +1998,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
buildSettings->AddAttribute("MACH_O_TYPE",
@@ -2050,7 +2039,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// a per-configuration Info.plist file. The cfbundle plist
// is very similar to the application bundle plist
this->CurrentLocalGenerator->GenerateAppleInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
@@ -2084,7 +2073,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
@@ -2122,7 +2111,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the executable name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateAppleInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
}
@@ -2130,9 +2119,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
default:
break;
}
- if (this->XcodeVersion < 40) {
- buildSettings->AddAttribute("PREBINDING", this->CreateString("NO"));
- }
BuildObjectListOrString dirs(this, true);
BuildObjectListOrString fdirs(this, true);
@@ -2497,12 +2483,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
cmGeneratorTarget* gtgt)
{
- std::string configTypes =
- this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
- std::vector<std::string> configVectorIn;
- std::vector<std::string> configVector;
- configVectorIn.push_back(configTypes);
- cmSystemTools::ExpandList(configVectorIn, configVector);
+ std::vector<std::string> const configVector =
+ cmSystemTools::ExpandedListArgument(
+ this->CurrentMakefile->GetRequiredDefinition(
+ "CMAKE_CONFIGURATION_TYPES"));
cmXCodeObject* configlist =
this->CreateObject(cmXCodeObject::XCConfigurationList);
cmXCodeObject* buildConfigurations =
@@ -2782,8 +2766,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
// Loop over configuration types and set per-configuration info.
for (auto const& configName : this->CurrentConfigurationTypes) {
- // Get the current configuration name.
- if (this->XcodeVersion >= 50) {
+ {
// Add object library contents as link flags.
std::string linkObjs;
const char* sep = "";
@@ -2893,7 +2876,7 @@ bool cmGlobalXCodeGenerator::CreateGroups(
// Put cmSourceFile instances in proper groups:
for (auto const& si : gtgt->GetAllConfigSources()) {
cmSourceFile const* sf = si.Source;
- if (this->XcodeVersion >= 50 && !sf->GetObjectLibrary().empty()) {
+ if (!sf->GetObjectLibrary().empty()) {
// Object library files go on the link line instead.
continue;
}
@@ -3029,10 +3012,11 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
- for (auto& CurrentConfigurationType : this->CurrentConfigurationTypes) {
+ for (const std::string& CurrentConfigurationType :
+ this->CurrentConfigurationTypes) {
cmXCodeObject* buildStyle =
this->CreateObject(cmXCodeObject::PBXBuildStyle);
- const char* name = CurrentConfigurationType.c_str();
+ const std::string& name = CurrentConfigurationType;
buildStyle->AddAttribute("name", this->CreateString(name));
buildStyle->SetComment(name);
cmXCodeObject* sgroup = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
@@ -3081,20 +3065,12 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
v << std::setfill('0') << std::setw(4) << XcodeVersion * 10;
group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str()));
this->RootObject->AddAttribute("attributes", group);
- if (this->XcodeVersion >= 32) {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.2"));
- } else if (this->XcodeVersion >= 31) {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.1"));
- } else {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.0"));
- }
+ this->RootObject->AddAttribute("compatibilityVersion",
+ this->CreateString("Xcode 3.2"));
// Point Xcode at the top of the source tree.
{
std::string pdir =
- this->RelativeToBinary(root->GetCurrentSourceDirectory().c_str());
+ this->RelativeToBinary(root->GetCurrentSourceDirectory());
this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
}
@@ -3286,8 +3262,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
{
cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile);
if (!makefileStream) {
- cmSystemTools::Error("Could not create",
- this->CurrentXCodeHackMakefile.c_str());
+ cmSystemTools::Error("Could not create " + this->CurrentXCodeHackMakefile);
return;
}
makefileStream.SetCopyIfDifferent(true);
@@ -3424,7 +3399,7 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
xcodeDir += "/";
xcodeDir += root->GetProjectName();
xcodeDir += ".xcodeproj";
- cmSystemTools::MakeDirectory(xcodeDir.c_str());
+ cmSystemTools::MakeDirectory(xcodeDir);
std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
cmGeneratedFileStream fout(xcodeProjFile);
fout.SetCopyIfDifferent(true);
@@ -3433,10 +3408,8 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
}
this->WriteXCodePBXProj(fout, root, generators);
- if (this->IsGeneratingScheme(root)) {
- this->OutputXCodeSharedSchemes(xcodeDir);
- }
- this->OutputXCodeWorkspaceSettings(xcodeDir, root);
+ bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root);
+ this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes);
this->ClearXCodeObjects();
@@ -3446,17 +3419,8 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
root->GetBinaryDirectory());
}
-bool cmGlobalXCodeGenerator::IsGeneratingScheme(cmLocalGenerator* root) const
-{
- // Since the lowest available Xcode version for testing was 6.4,
- // I'm setting this as a limit then
- return this->XcodeVersion >= 64 &&
- (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
- root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_SCHEME"));
-}
-
-void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
- const std::string& xcProjDir)
+bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
+ const std::string& xcProjDir, cmLocalGenerator* root)
{
// collect all tests for the targets
std::map<std::string, cmXCodeScheme::TestObjects> testables;
@@ -3480,21 +3444,33 @@ void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
}
// generate scheme
- for (auto obj : this->XCodeObjects) {
- if (obj->GetType() == cmXCodeObject::OBJECT &&
- (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
- obj->GetIsA() == cmXCodeObject::PBXAggregateTarget)) {
- const std::string& targetName = obj->GetTarget()->GetName();
- cmXCodeScheme schm(obj, testables[targetName],
- this->CurrentConfigurationTypes, this->XcodeVersion);
- schm.WriteXCodeSharedScheme(xcProjDir,
- this->RelativeToSource(xcProjDir.c_str()));
+ bool ret = false;
+
+ // Since the lowest available Xcode version for testing was 6.4,
+ // I'm setting this as a limit then
+ if (this->XcodeVersion >= 64) {
+ for (auto obj : this->XCodeObjects) {
+ if (obj->GetType() == cmXCodeObject::OBJECT &&
+ (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
+ obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) &&
+ (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
+ obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
+ const std::string& targetName = obj->GetTarget()->GetName();
+ cmXCodeScheme schm(obj, testables[targetName],
+ this->CurrentConfigurationTypes,
+ this->XcodeVersion);
+ schm.WriteXCodeSharedScheme(xcProjDir,
+ this->RelativeToSource(xcProjDir));
+ ret = true;
+ }
}
}
+
+ return ret;
}
void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
- const std::string& xcProjDir, cmLocalGenerator* root)
+ const std::string& xcProjDir, bool hasGeneratedSchemes)
{
std::string xcodeSharedDataDir = xcProjDir;
xcodeSharedDataDir += "/project.xcworkspace/xcshareddata";
@@ -3520,7 +3496,7 @@ void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
xout.Element("key", "BuildSystemType");
xout.Element("string", "Original");
}
- if (this->IsGeneratingScheme(root)) {
+ if (hasGeneratedSchemes) {
xout.Element("key",
"IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded");
xout.Element("false");
@@ -3545,13 +3521,7 @@ void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
cmXCodeObject::Indent(1, fout);
fout << "};\n";
cmXCodeObject::Indent(1, fout);
- if (this->XcodeVersion >= 32) {
- fout << "objectVersion = 46;\n";
- } else if (this->XcodeVersion >= 31) {
- fout << "objectVersion = 45;\n";
- } else {
- fout << "objectVersion = 44;\n";
- }
+ fout << "objectVersion = 46;\n";
cmXCode21Object::PrintList(this->XCodeObjects, fout);
cmXCodeObject::Indent(1, fout);
fout << "rootObject = " << this->RootObject->GetId()
@@ -3596,7 +3566,7 @@ std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
return cmSystemTools::ConvertToOutputPath(p);
}
-std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
{
// We force conversion because Xcode breakpoints do not work unless
// they are in a file named relative to the source tree.
@@ -3604,7 +3574,7 @@ std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
cmSystemTools::JoinPath(this->ProjectSourceDirectoryComponents), p);
}
-std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p)
{
return this->CurrentLocalGenerator->MaybeConvertToRelativePath(
cmSystemTools::JoinPath(this->ProjectOutputDirectoryComponents), p);
@@ -3719,11 +3689,7 @@ void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
// Flag value with escaped quotes and backslashes.
for (auto c : flag) {
if (c == '\'') {
- if (this->XcodeVersion >= 40) {
- flags += "'\\''";
- } else {
- flags += "\\'";
- }
+ flags += "'\\''";
} else if (c == '\\') {
flags += "\\\\";
} else {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index e1e412dca..71446f997 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -36,7 +36,7 @@ public:
unsigned int version_number);
static cmGlobalGeneratorFactory* NewFactory();
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalXCodeGenerator::GetActualName();
@@ -46,7 +46,7 @@ public:
/** Get the documentation entry for this generator. */
static void GetDocumentation(cmDocumentationEntry& entry);
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -66,15 +66,12 @@ public:
* Try running cmake and building a file. This is used for dynalically
* loaded commands, not as part of the usual build process.
*/
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/** Append the subdirectory for the given configuration. */
void AppendDirectoryForConfig(const std::string& prefix,
@@ -84,9 +81,9 @@ public:
bool FindMakeProgram(cmMakefile*) override;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
const char* GetCMakeCFGIntDir() const override;
- ///! expand CFGIntDir
+ //! expand CFGIntDir
std::string ExpandCFGIntDir(const std::string& str,
const std::string& config) const override;
@@ -122,8 +119,8 @@ private:
const std::string& name);
bool CreateGroups(std::vector<cmLocalGenerator*>& generators);
std::string XCodeEscapePath(const std::string& p);
- std::string RelativeToSource(const char* p);
- std::string RelativeToBinary(const char* p);
+ std::string RelativeToSource(const std::string& p);
+ std::string RelativeToBinary(const std::string& p);
std::string ConvertToRelativeForMake(std::string const& p);
void CreateCustomCommands(cmXCodeObject* buildPhases,
cmXCodeObject* sourceBuildPhase,
@@ -189,11 +186,12 @@ private:
std::vector<cmLocalGenerator*>& generators);
void OutputXCodeProject(cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
- bool IsGeneratingScheme(cmLocalGenerator* root) const;
// Write shared scheme files for all the native targets
- void OutputXCodeSharedSchemes(const std::string& xcProjDir);
+ // return true if any were written
+ bool OutputXCodeSharedSchemes(const std::string& xcProjDir,
+ cmLocalGenerator* root);
void OutputXCodeWorkspaceSettings(const std::string& xcProjDir,
- cmLocalGenerator* root);
+ bool hasGeneratedSchemes);
void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 4b6027995..a75d8a97a 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -170,8 +170,9 @@ cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator)
{
}
-void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
- const char* fallbackSettingsFileName)
+void cmGraphVizWriter::ReadSettings(
+ const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName)
{
cmake cm(cmake::RoleScript, cmState::Unknown);
cm.SetHomeDirectory("");
@@ -181,8 +182,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
cmMakefile mf(&ggi, cm.GetCurrentSnapshot());
std::unique_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator(&mf));
- const char* inFileName = settingsFileName;
-
+ std::string inFileName = settingsFileName;
if (!cmSystemTools::FileExists(inFileName)) {
inFileName = fallbackSettingsFileName;
if (!cmSystemTools::FileExists(inFileName)) {
@@ -191,7 +191,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
}
if (!mf.ReadListFile(inFileName)) {
- cmSystemTools::Error("Problem opening GraphViz options file: ",
+ cmSystemTools::Error("Problem opening GraphViz options file: " +
inFileName);
return;
}
@@ -249,7 +249,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
// Iterate over all targets and write for each one a graph which shows
// which other targets depend on it.
-void cmGraphVizWriter::WriteTargetDependersFiles(const char* fileName)
+void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName)
{
if (!this->GenerateDependers) {
return;
@@ -291,7 +291,7 @@ void cmGraphVizWriter::WriteTargetDependersFiles(const char* fileName)
// Iterate over all targets and write for each one a graph which shows
// on which targets it depends.
-void cmGraphVizWriter::WritePerTargetFiles(const char* fileName)
+void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName)
{
if (!this->GeneratePerTarget) {
return;
@@ -327,7 +327,7 @@ void cmGraphVizWriter::WritePerTargetFiles(const char* fileName)
}
}
-void cmGraphVizWriter::WriteGlobalFile(const char* fileName)
+void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName)
{
this->CollectTargetsAndLibs();
@@ -392,7 +392,7 @@ void cmGraphVizWriter::WriteConnections(
GlobalGenerator);
for (auto const& llit : ll) {
- const char* libName = llit.first.c_str();
+ const std::string& libName = llit.first;
std::map<std::string, std::string>::const_iterator libNameIt =
this->TargetNamesNodes.find(libName);
@@ -519,7 +519,7 @@ int cmGraphVizWriter::CollectAllTargets()
for (cmLocalGenerator* lg : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
for (cmGeneratorTarget* target : targets) {
- const char* realTargetName = target->GetName().c_str();
+ const std::string& realTargetName = target->GetName();
if (this->IgnoreThisTarget(realTargetName)) {
// Skip ignored targets
continue;
@@ -541,7 +541,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
for (cmLocalGenerator* lg : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
for (cmGeneratorTarget* target : targets) {
- const char* realTargetName = target->GetName().c_str();
+ const std::string& realTargetName = target->GetName();
if (this->IgnoreThisTarget(realTargetName)) {
// Skip ignored targets
continue;
@@ -549,7 +549,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
const cmTarget::LinkLibraryVectorType* ll =
&(target->Target->GetOriginalLinkLibraries());
for (auto const& llit : *ll) {
- const char* libName = llit.first.c_str();
+ std::string libName = llit.first;
if (this->IgnoreThisTarget(libName)) {
// Skip ignored targets
continue;
@@ -558,7 +558,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
if (GlobalGenerator->IsAlias(libName)) {
const auto tgt = GlobalGenerator->FindTarget(libName);
if (tgt) {
- libName = tgt->GetName().c_str();
+ libName = tgt->GetName();
}
}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index ed242f0ab..768683a3b 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -25,13 +25,13 @@ class cmGraphVizWriter
public:
cmGraphVizWriter(const cmGlobalGenerator* globalGenerator);
- void ReadSettings(const char* settingsFileName,
- const char* fallbackSettingsFileName);
+ void ReadSettings(const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName);
- void WritePerTargetFiles(const char* fileName);
- void WriteTargetDependersFiles(const char* fileName);
+ void WritePerTargetFiles(const std::string& fileName);
+ void WriteTargetDependersFiles(const std::string& fileName);
- void WriteGlobalFile(const char* fileName);
+ void WriteGlobalFile(const std::string& fileName);
protected:
void CollectTargetsAndLibs();
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
index 4e29f399a..190f2e305 100644
--- a/Source/cmHexFileConverter.cxx
+++ b/Source/cmHexFileConverter.cxx
@@ -128,7 +128,7 @@ static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
}
cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
- const char* inFileName)
+ const std::string& inFileName)
{
char buf[1024];
FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
@@ -170,8 +170,8 @@ cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
return type;
}
-bool cmHexFileConverter::TryConvert(const char* inFileName,
- const char* outFileName)
+bool cmHexFileConverter::TryConvert(const std::string& inFileName,
+ const std::string& outFileName)
{
FileType type = DetermineFileType(inFileName);
if (type == Binary) {
diff --git a/Source/cmHexFileConverter.h b/Source/cmHexFileConverter.h
index 25278e4a3..cb5de8f34 100644
--- a/Source/cmHexFileConverter.h
+++ b/Source/cmHexFileConverter.h
@@ -4,6 +4,7 @@
#define cmHexFileConverter_h
#include "cmConfigure.h" // IWYU pragma: keep
+#include <string>
/** \class cmHexFileConverter
* \brief Can detects Intel Hex and Motorola S-record files and convert them
@@ -19,8 +20,9 @@ public:
IntelHex,
MotorolaSrec
};
- static FileType DetermineFileType(const char* inFileName);
- static bool TryConvert(const char* inFileName, const char* outFileName);
+ static FileType DetermineFileType(const std::string& inFileName);
+ static bool TryConvert(const std::string& inFileName,
+ const std::string& outFileName);
};
#endif
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
index ea67d45fa..7b992d743 100644
--- a/Source/cmIDEOptions.cxx
+++ b/Source/cmIDEOptions.cxx
@@ -6,6 +6,7 @@
#include <iterator>
#include <string.h>
+#include "cmAlgorithms.h"
#include "cmIDEFlagTable.h"
#include "cmSystemTools.h"
@@ -170,7 +171,7 @@ void cmIDEOptions::AddDefines(std::string const& defines)
}
void cmIDEOptions::AddDefines(const std::vector<std::string>& defines)
{
- this->Defines.insert(this->Defines.end(), defines.begin(), defines.end());
+ cmAppend(this->Defines, defines);
}
std::vector<std::string> const& cmIDEOptions::GetDefines() const
@@ -192,8 +193,7 @@ void cmIDEOptions::AddIncludes(std::string const& includes)
}
void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes)
{
- this->Includes.insert(this->Includes.end(), includes.begin(),
- includes.end());
+ cmAppend(this->Includes, includes);
}
std::vector<std::string> const& cmIDEOptions::GetIncludes() const
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
index 549a263e3..62e2abdcd 100644
--- a/Source/cmIncludeDirectoryCommand.cxx
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -6,6 +6,7 @@
#include <set>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -52,11 +53,9 @@ bool cmIncludeDirectoryCommand::InitialPass(
this->GetIncludes(*i, includes);
if (before) {
- beforeIncludes.insert(beforeIncludes.end(), includes.begin(),
- includes.end());
+ cmAppend(beforeIncludes, includes);
} else {
- afterIncludes.insert(afterIncludes.end(), includes.begin(),
- includes.end());
+ cmAppend(afterIncludes, includes);
}
if (system) {
systemIncludes.insert(includes.begin(), includes.end());
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 20d1a3134..dba4bbb30 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/Glob.hxx"
#include <set>
#include <sstream>
@@ -9,7 +10,7 @@
#include <utility>
#include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
#include "cmExportSet.h"
#include "cmExportSetMap.h"
#include "cmGeneratorExpression.h"
@@ -219,49 +220,51 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
return true;
}
-/*struct InstallPart
-{
- InstallPart(cmCommandArgumentsHelper* helper, const char* key,
- cmCommandArgumentGroup* group);
- cmCAStringVector argVector;
- cmInstallCommandArguments args;
-};*/
-
bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
{
// This is the TARGETS mode.
std::vector<cmTarget*> targets;
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
- cmCAStringVector genericArgVector(&argHelper, nullptr);
- cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
- cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
- cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group);
- cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group);
- cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group);
- cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group);
- cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group);
- cmCAStringVector privateHeaderArgVector(&argHelper, "PRIVATE_HEADER",
- &group);
- cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group);
- cmCAStringVector resourceArgVector(&argHelper, "RESOURCE", &group);
- genericArgVector.Follows(nullptr);
- group.Follows(&genericArgVector);
-
- argHelper.Parse(&args, nullptr);
+ struct ArgVectors
+ {
+ std::vector<std::string> Archive;
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Object;
+ std::vector<std::string> Framework;
+ std::vector<std::string> Bundle;
+ std::vector<std::string> Includes;
+ std::vector<std::string> PrivateHeader;
+ std::vector<std::string> PublicHeader;
+ std::vector<std::string> Resource;
+ };
+
+ static auto const argHelper =
+ cmArgumentParser<ArgVectors>{}
+ .Bind("ARCHIVE"_s, &ArgVectors::Archive)
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("OBJECTS"_s, &ArgVectors::Object)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+ .Bind("BUNDLE"_s, &ArgVectors::Bundle)
+ .Bind("INCLUDES"_s, &ArgVectors::Includes)
+ .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
+ .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
+ .Bind("RESOURCE"_s, &ArgVectors::Resource);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
// now parse the generic args (i.e. the ones not specialized on LIBRARY/
// ARCHIVE, RUNTIME etc. (see above)
// These generic args also contain the targets and the export stuff
+ std::vector<std::string> targetList;
+ std::string exports;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(this->DefaultComponentName);
- cmCAStringVector targetList(&genericArgs.Parser, "TARGETS");
- cmCAString exports(&genericArgs.Parser, "EXPORT",
- &genericArgs.ArgumentGroup);
- targetList.Follows(nullptr);
- genericArgs.ArgumentGroup.Follows(&targetList);
- genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs);
+ genericArgs.Bind("TARGETS"_s, targetList);
+ genericArgs.Bind("EXPORT"_s, exports);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
@@ -277,16 +280,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME, ARCHIVE etc.
- archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs);
- libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs);
- runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs);
- objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs);
- frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs);
- bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs);
- privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
- publicHeaderArgs.Parse(&publicHeaderArgVector.GetVector(), &unknownArgs);
- resourceArgs.Parse(&resourceArgVector.GetVector(), &unknownArgs);
- includesArgs.Parse(&includesArgVector.GetVector(), &unknownArgs);
+ archiveArgs.Parse(argVectors.Archive, &unknownArgs);
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ objectArgs.Parse(argVectors.Object, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+ bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+ privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
+ publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
+ resourceArgs.Parse(argVectors.Resource, &unknownArgs);
+ includesArgs.Parse(&argVectors.Includes, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -382,7 +385,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
}
// Check if there is something to do.
- if (targetList.GetVector().empty()) {
+ if (targetList.empty()) {
return true;
}
@@ -390,7 +393,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
bool dll_platform =
!this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
- for (std::string const& tgt : targetList.GetVector()) {
+ for (std::string const& tgt : targetList) {
if (this->Makefile->IsAlias(tgt)) {
std::ostringstream e;
@@ -663,8 +666,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// generators for them.
bool createInstallGeneratorsForTargetFileSets = true;
- if (target.IsFrameworkOnApple() ||
- target.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ if (target.IsFrameworkOnApple()) {
createInstallGeneratorsForTargetFileSets = false;
}
@@ -748,7 +750,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// Add this install rule to an export if one was specified and
// this is not a namelink-only rule.
- if (!exports.GetString().empty() && !namelinkOnly) {
+ if (!exports.empty() && !namelinkOnly) {
cmTargetExport* te = new cmTargetExport;
te->TargetName = target.GetName();
te->ArchiveGenerator = archiveGenerator;
@@ -759,7 +761,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
te->RuntimeGenerator = runtimeGenerator;
te->ObjectsGenerator = objectGenerator;
this->Makefile->GetGlobalGenerator()
- ->GetExportSets()[exports.GetString()]
+ ->GetExportSets()[exports]
->AddTargetExport(te);
te->InterfaceIncludeDirectories =
@@ -818,11 +820,10 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args)
// This is the FILES mode.
bool programs = (args[0] == "PROGRAMS");
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAStringVector files(&ica.Parser, programs ? "PROGRAMS" : "FILES");
- files.Follows(nullptr);
- ica.ArgumentGroup.Follows(&files);
+ std::vector<std::string> files;
+ ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -840,7 +841,7 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args)
return false;
}
- const std::vector<std::string>& filesVector = files.GetVector();
+ const std::vector<std::string>& filesVector = files;
// Check if there is something to do.
if (filesVector.empty()) {
@@ -1271,16 +1272,19 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
#ifdef CMAKE_BUILD_WITH_CMAKE
// This is the EXPORT mode.
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAString exp(&ica.Parser, "EXPORT_ANDROID_MK");
- cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
- cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
- &ica.ArgumentGroup);
- cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
- exp.Follows(nullptr);
-
- ica.ArgumentGroup.Follows(&exp);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT_ANDROID_MK"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -1304,7 +1308,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
// Check the file name.
- std::string fname = filename.GetString();
+ std::string fname = filename;
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
e << args[0] << " given invalid export file name \"" << fname << "\". "
@@ -1325,7 +1329,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
- e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ e << args[0] << " given export name \"" << exp << "\". "
<< "This name cannot be safely converted to a file name. "
<< "Specify a different export name or use the FILE option to set "
<< "a file name explicitly.";
@@ -1338,7 +1342,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
cmExportSet* exportSet =
- this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
+ this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
cmInstallGenerator::MessageLevel message =
cmInstallGenerator::SelectMessageLevel(this->Makefile);
@@ -1347,8 +1351,8 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
ica.GetConfigurations(), ica.GetComponent().c_str(), message,
- ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
- exportOld.IsEnabled(), true);
+ ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+ true);
this->Makefile->AddInstallGenerator(exportGenerator);
return true;
@@ -1363,16 +1367,19 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
{
// This is the EXPORT mode.
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAString exp(&ica.Parser, "EXPORT");
- cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
- cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
- &ica.ArgumentGroup);
- cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
- exp.Follows(nullptr);
-
- ica.ArgumentGroup.Follows(&exp);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -1396,7 +1403,7 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
}
// Check the file name.
- std::string fname = filename.GetString();
+ std::string fname = filename;
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
e << args[0] << " given invalid export file name \"" << fname << "\". "
@@ -1418,12 +1425,12 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
// Construct the file name.
if (fname.empty()) {
- fname = exp.GetString();
+ fname = exp;
fname += ".cmake";
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
- e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ e << args[0] << " given export name \"" << exp << "\". "
<< "This name cannot be safely converted to a file name. "
<< "Specify a different export name or use the FILE option to set "
<< "a file name explicitly.";
@@ -1433,8 +1440,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
}
cmExportSet* exportSet =
- this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
- if (exportOld.IsEnabled()) {
+ this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
+ if (exportOld) {
for (cmTargetExport* te : *exportSet->GetTargetExports()) {
cmTarget* tgt =
this->Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
@@ -1461,8 +1468,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
ica.GetConfigurations(), ica.GetComponent().c_str(), message,
- ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
- exportOld.IsEnabled(), false);
+ ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+ false);
this->Makefile->AddInstallGenerator(exportGenerator);
return true;
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
index 155f0559b..8b33782ae 100644
--- a/Source/cmInstallCommandArguments.cxx
+++ b/Source/cmInstallCommandArguments.cxx
@@ -2,7 +2,9 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommandArguments.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
#include <utility>
@@ -17,20 +19,19 @@ const std::string cmInstallCommandArguments::EmptyString;
cmInstallCommandArguments::cmInstallCommandArguments(
std::string defaultComponent)
- : Destination(&Parser, "DESTINATION", &ArgumentGroup)
- , Component(&Parser, "COMPONENT", &ArgumentGroup)
- , NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup)
- , ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
- , Rename(&Parser, "RENAME", &ArgumentGroup)
- , Permissions(&Parser, "PERMISSIONS", &ArgumentGroup)
- , Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup)
- , Optional(&Parser, "OPTIONAL", &ArgumentGroup)
- , NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup)
- , NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup)
- , Type(&Parser, "TYPE", &ArgumentGroup)
- , GenericArguments(nullptr)
- , DefaultComponentName(std::move(defaultComponent))
+ : DefaultComponentName(std::move(defaultComponent))
{
+ this->Bind("DESTINATION"_s, this->Destination);
+ this->Bind("COMPONENT"_s, this->Component);
+ this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent);
+ this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll);
+ this->Bind("RENAME"_s, this->Rename);
+ this->Bind("PERMISSIONS"_s, this->Permissions);
+ this->Bind("CONFIGURATIONS"_s, this->Configurations);
+ this->Bind("OPTIONAL"_s, this->Optional);
+ this->Bind("NAMELINK_ONLY"_s, this->NamelinkOnly);
+ this->Bind("NAMELINK_SKIP"_s, this->NamelinkSkip);
+ this->Bind("TYPE"_s, this->Type);
}
const std::string& cmInstallCommandArguments::GetDestination() const
@@ -46,8 +47,8 @@ const std::string& cmInstallCommandArguments::GetDestination() const
const std::string& cmInstallCommandArguments::GetComponent() const
{
- if (!this->Component.GetString().empty()) {
- return this->Component.GetString();
+ if (!this->Component.empty()) {
+ return this->Component;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetComponent();
@@ -61,16 +62,16 @@ const std::string& cmInstallCommandArguments::GetComponent() const
const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
{
- if (!this->NamelinkComponent.GetString().empty()) {
- return this->NamelinkComponent.GetString();
+ if (!this->NamelinkComponent.empty()) {
+ return this->NamelinkComponent;
}
return this->GetComponent();
}
const std::string& cmInstallCommandArguments::GetRename() const
{
- if (!this->Rename.GetString().empty()) {
- return this->Rename.GetString();
+ if (!this->Rename.empty()) {
+ return this->Rename;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetRename();
@@ -91,7 +92,7 @@ const std::string& cmInstallCommandArguments::GetPermissions() const
bool cmInstallCommandArguments::GetOptional() const
{
- if (this->Optional.IsEnabled()) {
+ if (this->Optional) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -102,7 +103,7 @@ bool cmInstallCommandArguments::GetOptional() const
bool cmInstallCommandArguments::GetExcludeFromAll() const
{
- if (this->ExcludeFromAll.IsEnabled()) {
+ if (this->ExcludeFromAll) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -113,7 +114,7 @@ bool cmInstallCommandArguments::GetExcludeFromAll() const
bool cmInstallCommandArguments::GetNamelinkOnly() const
{
- if (this->NamelinkOnly.IsEnabled()) {
+ if (this->NamelinkOnly) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -124,7 +125,7 @@ bool cmInstallCommandArguments::GetNamelinkOnly() const
bool cmInstallCommandArguments::GetNamelinkSkip() const
{
- if (this->NamelinkSkip.IsEnabled()) {
+ if (this->NamelinkSkip) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -135,7 +136,7 @@ bool cmInstallCommandArguments::GetNamelinkSkip() const
bool cmInstallCommandArguments::HasNamelinkComponent() const
{
- if (!this->NamelinkComponent.GetString().empty()) {
+ if (!this->NamelinkComponent.empty()) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -146,19 +147,19 @@ bool cmInstallCommandArguments::HasNamelinkComponent() const
const std::string& cmInstallCommandArguments::GetType() const
{
- return this->Type.GetString();
+ return this->Type;
}
const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
const
{
- if (!this->Configurations.GetVector().empty()) {
- return this->Configurations.GetVector();
+ if (!this->Configurations.empty()) {
+ return this->Configurations;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetConfigurations();
}
- return this->Configurations.GetVector();
+ return this->Configurations;
}
bool cmInstallCommandArguments::Finalize()
@@ -166,21 +167,15 @@ bool cmInstallCommandArguments::Finalize()
if (!this->CheckPermissions()) {
return false;
}
- this->DestinationString = this->Destination.GetString();
+ this->DestinationString = this->Destination;
cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
return true;
}
-void cmInstallCommandArguments::Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs)
-{
- this->Parser.Parse(args, unconsumedArgs);
-}
-
bool cmInstallCommandArguments::CheckPermissions()
{
this->PermissionsString.clear();
- for (std::string const& perm : this->Permissions.GetVector()) {
+ for (std::string const& perm : this->Permissions) {
if (!cmInstallCommandArguments::CheckPermissions(
perm, this->PermissionsString)) {
return false;
@@ -220,10 +215,7 @@ void cmInstallCommandIncludesArgument::Parse(
if (args->empty()) {
return;
}
- std::vector<std::string>::const_iterator it = args->begin();
- ++it;
- for (; it != args->end(); ++it) {
- std::string dir = *it;
+ for (std::string dir : cmMakeRange(*args).advance(1)) {
cmSystemTools::ConvertToUnixSlashes(dir);
this->IncludeDirs.push_back(std::move(dir));
}
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 9c0d41763..5d2ee0ab4 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -8,9 +8,9 @@
#include <string>
#include <vector>
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
-class cmInstallCommandArguments
+class cmInstallCommandArguments : public cmArgumentParser<void>
{
public:
cmInstallCommandArguments(std::string defaultComponent);
@@ -18,8 +18,6 @@ public:
{
this->GenericArguments = args;
}
- void Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs);
// Compute destination path.and check permissions
bool Finalize();
@@ -37,30 +35,25 @@ public:
bool HasNamelinkComponent() const;
const std::string& GetType() const;
- // once HandleDirectoryMode() is also switched to using
- // cmInstallCommandArguments then these two functions can become non-static
- // private member functions without arguments
static bool CheckPermissions(const std::string& onePerm, std::string& perm);
- cmCommandArgumentsHelper Parser;
- cmCommandArgumentGroup ArgumentGroup;
private:
- cmCAString Destination;
- cmCAString Component;
- cmCAString NamelinkComponent;
- cmCAEnabler ExcludeFromAll;
- cmCAString Rename;
- cmCAStringVector Permissions;
- cmCAStringVector Configurations;
- cmCAEnabler Optional;
- cmCAEnabler NamelinkOnly;
- cmCAEnabler NamelinkSkip;
- cmCAString Type;
+ std::string Destination;
+ std::string Component;
+ std::string NamelinkComponent;
+ bool ExcludeFromAll = false;
+ std::string Rename;
+ std::vector<std::string> Permissions;
+ std::vector<std::string> Configurations;
+ bool Optional = false;
+ bool NamelinkOnly = false;
+ bool NamelinkSkip = false;
+ std::string Type;
std::string DestinationString;
std::string PermissionsString;
- cmInstallCommandArguments* GenericArguments;
+ cmInstallCommandArguments* GenericArguments = nullptr;
static const char* PermissionsTable[];
static const std::string EmptyString;
std::string DefaultComponentName;
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index a88c7af3b..14288f6d2 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -31,19 +31,22 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
}
// We need per-config actions if any directories have generator expressions.
- for (std::vector<std::string>::const_iterator i = dirs.begin();
- !this->ActionsPerConfig && i != dirs.end(); ++i) {
- if (cmGeneratorExpression::Find(*i) != std::string::npos) {
- this->ActionsPerConfig = true;
+ if (!this->ActionsPerConfig) {
+ for (std::string const& dir : dirs) {
+ if (cmGeneratorExpression::Find(dir) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
}
}
}
cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default;
-void cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
{
- LocalGenerator = lg;
+ this->LocalGenerator = lg;
+ return true;
}
void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index ac6e50457..e30849f83 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallDirectoryGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx
index 85b702142..55d368507 100644
--- a/Source/cmInstallExportAndroidMKGenerator.cxx
+++ b/Source/cmInstallExportAndroidMKGenerator.cxx
@@ -30,10 +30,11 @@ cmInstallExportAndroidMKGenerator::~cmInstallExportAndroidMKGenerator()
{
}
-void cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
@@ -43,7 +44,7 @@ void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
std::ostringstream e;
e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName()
<< "\"";
- cmSystemTools::Error(e.str().c_str());
+ cmSystemTools::Error(e.str());
return;
}
@@ -67,10 +68,8 @@ void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
this->EFGen->AddConfiguration("");
}
} else {
- for (std::vector<std::string>::const_iterator ci =
- this->ConfigurationTypes->begin();
- ci != this->ConfigurationTypes->end(); ++ci) {
- this->EFGen->AddConfiguration(*ci);
+ for (std::string const& config : this->ConfigurationTypes) {
+ this->EFGen->AddConfiguration(config);
}
}
this->EFGen->GenerateImportFile();
@@ -88,11 +87,9 @@ void cmInstallExportAndroidMKGenerator::GenerateScriptConfigs(
// Now create a configuration-specific install rule for the import
// file of each configuration.
std::vector<std::string> files;
- for (std::map<std::string, std::string>::const_iterator i =
- this->EFGen->GetConfigImportFiles().begin();
- i != this->EFGen->GetConfigImportFiles().end(); ++i) {
- files.push_back(i->second);
- std::string config_test = this->CreateConfigTest(i->first);
+ for (auto const& pair : this->EFGen->GetConfigImportFiles()) {
+ files.push_back(pair.second);
+ std::string config_test = this->CreateConfigTest(pair.first);
os << indent << "if(" << config_test << ")\n";
this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
false, this->FilePermissions.c_str(), nullptr,
diff --git a/Source/cmInstallExportAndroidMKGenerator.h b/Source/cmInstallExportAndroidMKGenerator.h
index 189084a1a..a92ff27f1 100644
--- a/Source/cmInstallExportAndroidMKGenerator.h
+++ b/Source/cmInstallExportAndroidMKGenerator.h
@@ -24,7 +24,7 @@ public:
const char* name_space, bool exportOld);
~cmInstallExportAndroidMKGenerator();
- void Compute(cmLocalGenerator* lg);
+ bool Compute(cmLocalGenerator* lg) override;
protected:
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 47b9785e5..f5bedabc4 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -45,10 +45,11 @@ cmInstallExportGenerator::~cmInstallExportGenerator()
delete this->EFGen;
}
-void cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportGenerator::ComputeTempDir()
@@ -202,7 +203,7 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir
<< this->EFGen->GetConfigImportFileGlob() << "\")\n";
os << indentNN << "if(OLD_CONFIG_FILES)\n";
- os << indentNNN << "message(STATUS \"Old export file \\\"" << installedFile
+ os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
<< "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n";
os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n";
os << indentNN << "endif()\n";
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index d23cf063d..c4d252c47 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -34,7 +34,7 @@ public:
cmExportSet* GetExportSet() { return this->ExportSet; }
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; }
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
index 4dde18fb0..efbcb6713 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -2,11 +2,13 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallFilesCommand.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
class cmExecutionStatus;
@@ -27,16 +29,14 @@ bool cmInstallFilesCommand::InitialPass(std::vector<std::string> const& args,
if ((args.size() > 1) && (args[1] == "FILES")) {
this->IsFilesForm = true;
- for (std::vector<std::string>::const_iterator s = args.begin() + 2;
- s != args.end(); ++s) {
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
// Find the source location for each file listed.
- this->Files.push_back(this->FindInstallSource(s->c_str()));
+ this->Files.push_back(this->FindInstallSource(arg.c_str()));
}
this->CreateInstallGenerator();
} else {
this->IsFilesForm = false;
- this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1,
- args.end());
+ cmAppend(this->FinalArgs, args.begin() + 1, args.end());
}
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index 07094cb68..2ed9f734d 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -29,20 +29,23 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
this->ActionsPerConfig = true;
}
- // We need per-config actions if any files have generator expressions.
- for (std::vector<std::string>::const_iterator i = files.begin();
- !this->ActionsPerConfig && i != files.end(); ++i) {
- if (cmGeneratorExpression::Find(*i) != std::string::npos) {
- this->ActionsPerConfig = true;
+ // We need per-config actions if any directories have generator expressions.
+ if (!this->ActionsPerConfig) {
+ for (std::string const& file : files) {
+ if (cmGeneratorExpression::Find(file) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
}
}
}
cmInstallFilesGenerator::~cmInstallFilesGenerator() = default;
-void cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
std::string cmInstallFilesGenerator::GetDestination(
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index 0ef2a06b0..ac462d46f 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallFilesGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index d139190a4..2ffca30f6 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -69,17 +69,18 @@ void cmInstallGenerator::AddInstallRule(
if (cmSystemTools::FileIsFullPath(dest)) {
os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
os << indent << " \"";
- for (std::vector<std::string>::const_iterator fi = files.begin();
- fi != files.end(); ++fi) {
- if (fi != files.begin()) {
+ bool firstIteration = true;
+ for (std::string const& file : files) {
+ if (!firstIteration) {
os << ";";
}
os << dest << "/";
if (rename && *rename) {
os << rename;
} else {
- os << cmSystemTools::GetFilenameName(*fi);
+ os << cmSystemTools::GetFilenameName(file);
}
+ firstIteration = false;
}
os << "\")\n";
os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
@@ -141,7 +142,7 @@ void cmInstallGenerator::AddInstallRule(
std::string cmInstallGenerator::CreateComponentTest(const char* component,
bool exclude_from_all)
{
- std::string result = "\"x${CMAKE_INSTALL_COMPONENT}x\" STREQUAL \"x";
+ std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)";
result += component;
result += "x\"";
if (!exclude_from_all) {
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 9bd7ac318..dbe707d1d 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -60,7 +60,7 @@ public:
/** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
- virtual void Compute(cmLocalGenerator*) {}
+ virtual bool Compute(cmLocalGenerator*) { return true; }
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
index f01a4c1c4..a58f87578 100644
--- a/Source/cmInstallProgramsCommand.cxx
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallProgramsCommand.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallFilesGenerator.h"
@@ -25,7 +26,7 @@ bool cmInstallProgramsCommand::InitialPass(
this->Destination = args[0];
- this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1, args.end());
+ cmAppend(this->FinalArgs, args.begin() + 1, args.end());
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index a513958ed..5832d27e6 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -29,7 +29,7 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
cmInstallScriptGenerator::~cmInstallScriptGenerator() = default;
-void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
@@ -49,6 +49,8 @@ void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
break;
}
}
+
+ return true;
}
void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os,
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
index 05199d790..6af737113 100644
--- a/Source/cmInstallScriptGenerator.h
+++ b/Source/cmInstallScriptGenerator.h
@@ -23,7 +23,7 @@ public:
const char* component, bool exclude_from_all);
~cmInstallScriptGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScriptActions(std::ostream& os, Indent indent) override;
diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx
index ad7121f2e..1c0512ce5 100644
--- a/Source/cmInstallSubdirectoryGenerator.cxx
+++ b/Source/cmInstallSubdirectoryGenerator.cxx
@@ -41,9 +41,10 @@ void cmInstallSubdirectoryGenerator::CheckCMP0082(
}
}
-void cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os)
diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h
index 35471dda0..22759d948 100644
--- a/Source/cmInstallSubdirectoryGenerator.h
+++ b/Source/cmInstallSubdirectoryGenerator.h
@@ -28,7 +28,7 @@ public:
void CheckCMP0082(bool& haveSubdirectoryInstall,
bool& haveInstallAfterSubdirectory) override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 9d3a6bb60..7c5a55bb6 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -107,19 +107,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
// There is a bug in cmInstallCommand if this fails.
assert(this->NamelinkMode == NamelinkModeNone);
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->Target->GetExecutableNames(targetName, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetExecutableNames(config);
if (this->ImportLibrary) {
- std::string from1 = fromDirConfig + targetNameImport;
- std::string to1 = toDir + targetNameImport;
+ 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 targetNameImportLib;
- if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
targetNameImportLib)) {
filesFrom.push_back(fromDirConfig + targetNameImportLib);
filesTo.push_back(toDir + targetNameImportLib);
@@ -128,8 +124,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
// An import library looks like a static library.
type = cmInstallType_STATIC_LIBRARY;
} else {
- std::string from1 = fromDirConfig + targetName;
- std::string to1 = toDir + targetName;
+ std::string from1 = fromDirConfig + targetNames.Output;
+ std::string to1 = toDir + targetNames.Output;
// Handle OSX Bundles.
if (this->Target->IsAppBundleOnApple()) {
@@ -154,12 +150,12 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
if (!mf->PlatformIsAppleEmbedded()) {
to1 += "Contents/MacOS/";
}
- to1 += targetName;
+ to1 += targetNames.Output;
} else {
// Tweaks apply to the real file, so list it first.
- if (targetNameReal != targetName) {
- std::string from2 = fromDirConfig + targetNameReal;
- std::string to2 = toDir += targetNameReal;
+ 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));
}
@@ -169,23 +165,18 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
filesTo.push_back(std::move(to1));
}
} else {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetLibraryNames(config);
if (this->ImportLibrary) {
// There is a bug in cmInstallCommand if this fails.
assert(this->NamelinkMode == NamelinkModeNone);
- std::string from1 = fromDirConfig + targetNameImport;
- std::string to1 = toDir + targetNameImport;
+ 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 targetNameImportLib;
- if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
targetNameImportLib)) {
filesFrom.push_back(fromDirConfig + targetNameImportLib);
filesTo.push_back(toDir + targetNameImportLib);
@@ -227,11 +218,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
type = cmInstallType_DIRECTORY;
literal_args += " USE_SOURCE_PERMISSIONS";
- std::string from1 = fromDirConfig + targetName;
+ std::string from1 = fromDirConfig + targetNames.Output;
from1 = cmSystemTools::GetFilenamePath(from1);
// Tweaks apply to the binary inside the bundle.
- std::string to1 = toDir + targetNameReal;
+ std::string to1 = toDir + targetNames.Real;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
@@ -240,10 +231,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
type = cmInstallType_DIRECTORY;
literal_args += " USE_SOURCE_PERMISSIONS";
- std::string targetNameBase = targetName.substr(0, targetName.find('/'));
+ std::string targetNameBase =
+ targetNames.Output.substr(0, targetNames.Output.find('/'));
std::string from1 = fromDirConfig + targetNameBase;
- std::string to1 = toDir + targetName;
+ std::string to1 = toDir + targetNames.Output;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
@@ -251,25 +243,26 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
bool haveNamelink = false;
// Library link name.
- std::string fromName = fromDirConfig + targetName;
- std::string toName = toDir + targetName;
+ std::string fromName = fromDirConfig + targetNames.Output;
+ std::string toName = toDir + targetNames.Output;
// Library interface name.
std::string fromSOName;
std::string toSOName;
- if (targetNameSO != targetName) {
+ if (targetNames.SharedObject != targetNames.Output) {
haveNamelink = true;
- fromSOName = fromDirConfig + targetNameSO;
- toSOName = toDir + targetNameSO;
+ fromSOName = fromDirConfig + targetNames.SharedObject;
+ toSOName = toDir + targetNames.SharedObject;
}
// Library implementation name.
std::string fromRealName;
std::string toRealName;
- if (targetNameReal != targetName && targetNameReal != targetNameSO) {
+ if (targetNames.Real != targetNames.Output &&
+ targetNames.Real != targetNames.SharedObject) {
haveNamelink = true;
- fromRealName = fromDirConfig + targetNameReal;
- toRealName = toDir + targetNameReal;
+ fromRealName = fromDirConfig + targetNames.Real;
+ toRealName = toDir + targetNames.Real;
}
// Add the names based on the current namelink mode.
@@ -400,55 +393,44 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
std::string fname;
// Compute the name of the library.
if (target->GetType() == cmStateEnums::EXECUTABLE) {
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetExecutableNames(targetName, targetNameReal, targetNameImport,
- targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames = target->GetExecutableNames(config);
if (nameType == NameImplib) {
// Use the import library name.
- if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
- fname = targetNameImport;
+ fname = targetNames.ImportLibrary;
}
} else if (nameType == NameReal) {
// Use the canonical name.
- fname = targetNameReal;
+ fname = targetNames.Real;
} else {
// Use the canonical name.
- fname = targetName;
+ fname = targetNames.Output;
}
} else {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
if (nameType == NameImplib) {
// Use the import library name.
- if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
- fname = targetNameImport;
+ fname = targetNames.ImportLibrary;
}
} else if (nameType == NameSO) {
// Use the soname.
- fname = targetNameSO;
+ fname = targetNames.SharedObject;
} else if (nameType == NameReal) {
// Use the real name.
- fname = targetNameReal;
+ fname = targetNames.Real;
} else {
// Use the canonical name.
- fname = targetName;
+ fname = targetNames.Output;
}
}
return fname;
}
-void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
{
// Lookup this target in the current directory.
this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
@@ -457,6 +439,8 @@ void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
this->Target =
lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
}
+
+ return true;
}
void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
@@ -809,7 +793,7 @@ void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, Indent indent,
return;
}
- std::string ranlib =
+ const std::string& ranlib =
this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
if (ranlib.empty()) {
return;
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 6df5b1a50..ed3ab5246 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -58,7 +58,7 @@ public:
const std::string& config,
NameType nameType = NameNormal);
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmGeneratorTarget* GetTarget() const { return this->Target; }
diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx
index d721ca0ee..ef07e2cf4 100644
--- a/Source/cmInstallTargetsCommand.cxx
+++ b/Source/cmInstallTargetsCommand.cxx
@@ -23,7 +23,7 @@ bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args,
// Enable the install target.
this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
- cmTargets& tgts = this->Makefile->GetTargets();
+ cmMakefile::cmTargetMap& tgts = this->Makefile->GetTargets();
std::vector<std::string>::const_iterator s = args.begin();
++s;
std::string runtime_dir = "/bin";
@@ -38,10 +38,10 @@ bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args,
runtime_dir = *s;
} else {
- cmTargets::iterator ti = tgts.find(*s);
+ cmMakefile::cmTargetMap::iterator ti = tgts.find(*s);
if (ti != tgts.end()) {
- ti->second.SetInstallPath(args[0].c_str());
- ti->second.SetRuntimeInstallPath(runtime_dir.c_str());
+ ti->second.SetInstallPath(args[0]);
+ ti->second.SetRuntimeInstallPath(runtime_dir);
ti->second.SetHaveInstallRule(true);
} else {
std::string str = "Cannot find target: \"" + *s + "\" to install.";
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
index 070b954e6..b7d602ef4 100644
--- a/Source/cmInstalledFile.h
+++ b/Source/cmInstalledFile.h
@@ -32,6 +32,9 @@ public:
Property();
~Property();
+ Property(const Property&) = delete;
+ Property& operator=(const Property&) = delete;
+
ExpressionVectorType ValueExpressions;
};
@@ -41,6 +44,9 @@ public:
~cmInstalledFile();
+ cmInstalledFile(const cmInstalledFile&) = delete;
+ cmInstalledFile& operator=(const cmInstalledFile&) = delete;
+
void RemoveProperty(const std::string& prop);
void SetProperty(cmMakefile const* mf, const std::string& prop,
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index d723cedb5..636a8e1c2 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmJsonObjects.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -601,8 +602,7 @@ static Json::Value DumpTargetsList(
std::vector<cmGeneratorTarget*> targetList;
for (auto const& lgIt : generators) {
- const auto& list = lgIt->GetGeneratorTargets();
- targetList.insert(targetList.end(), list.begin(), list.end());
+ cmAppend(targetList, lgIt->GetGeneratorTargets());
}
std::sort(targetList.begin(), targetList.end());
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 211d03bd8..8d2add635 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -3,15 +3,21 @@
#include "cmLinkLineDeviceComputer.h"
+#include <algorithm>
#include <set>
#include <sstream>
#include <utility>
+#include <vector>
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
-#include "cmGlobalNinjaGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
+#include "cmSystemTools.h"
class cmOutputConverter;
@@ -41,6 +47,27 @@ static bool cmLinkItemValidForDevice(std::string const& item)
cmHasLiteralPrefix(item, "--library"));
}
+bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
+ cmComputeLinkInformation& cli)
+{
+ // Determine if this item might requires device linking.
+ // For this we only consider targets
+ typedef cmComputeLinkInformation::ItemVector 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")) {
+ // this dependency requires us to device link it
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString)
{
@@ -118,16 +145,58 @@ std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
return "CUDA";
}
-cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
- cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
- cmGlobalNinjaGenerator const* gg)
- : cmLinkLineDeviceComputer(outputConverter, stateDir)
- , GG(gg)
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config)
{
-}
+ if (!target.GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
+ return false;
+ }
-std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
- std::string const& lib) const
-{
- return GG->ConvertToNinjaPath(lib);
+ if (target.GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ return false;
+ }
+
+ if (const char* resolveDeviceSymbols =
+ target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
+ // If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
+ // to honor the value no matter what it is.
+ return cmSystemTools::IsOn(resolveDeviceSymbols);
+ }
+
+ if (const char* separableCompilation =
+ target.GetProperty("CUDA_SEPARABLE_COMPILATION")) {
+ if (cmSystemTools::IsOn(separableCompilation)) {
+ bool doDeviceLinking = false;
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::EXECUTABLE:
+ doDeviceLinking = true;
+ break;
+ default:
+ break;
+ }
+ return doDeviceLinking;
+ }
+ }
+
+ // Determine if we have any dependencies that require
+ // us to do a device link step
+ const std::string cuda_lang("CUDA");
+ cmGeneratorTarget::LinkClosure const* closure =
+ target.GetLinkClosure(config);
+
+ bool closureHasCUDA =
+ (std::find(closure->Languages.begin(), closure->Languages.end(),
+ cuda_lang) != closure->Languages.end());
+ if (closureHasCUDA) {
+ cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
+ if (pcli) {
+ cmLinkLineDeviceComputer deviceLinkComputer(
+ &lg, lg.GetStateSnapshot().GetDirectory());
+ return deviceLinkComputer.ComputeRequiresDeviceLinking(*pcli);
+ }
+ return true;
+ }
+ return false;
}
diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h
index cf66f6475..0ea5f69e7 100644
--- a/Source/cmLinkLineDeviceComputer.h
+++ b/Source/cmLinkLineDeviceComputer.h
@@ -12,7 +12,7 @@
class cmComputeLinkInformation;
class cmGeneratorTarget;
-class cmGlobalNinjaGenerator;
+class cmLocalGenerator;
class cmOutputConverter;
class cmStateDirectory;
@@ -27,6 +27,8 @@ public:
cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) =
delete;
+ bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
+
std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
std::string const& stdLibString) override;
@@ -34,21 +36,7 @@ public:
std::string const& config) override;
};
-class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer
-{
-public:
- cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter,
- cmStateDirectory const& stateDir,
- cmGlobalNinjaGenerator const* gg);
-
- cmNinjaLinkLineDeviceComputer(cmNinjaLinkLineDeviceComputer const&) = delete;
- cmNinjaLinkLineDeviceComputer& operator=(
- cmNinjaLinkLineDeviceComputer const&) = delete;
-
- std::string ConvertToLinkReference(std::string const& input) const override;
-
-private:
- cmGlobalNinjaGenerator const* GG;
-};
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config);
#endif
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 297babfd8..1b01ea202 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -19,6 +19,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
@@ -42,6 +43,15 @@ bool cmListCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "APPEND") {
return this->HandleAppendCommand(args);
}
+ if (subCommand == "PREPEND") {
+ return this->HandlePrependCommand(args);
+ }
+ if (subCommand == "POP_BACK") {
+ return this->HandlePopBackCommand(args);
+ }
+ if (subCommand == "POP_FRONT") {
+ return this->HandlePopFrontCommand(args);
+ }
if (subCommand == "FIND") {
return this->HandleFindCommand(args);
}
@@ -222,20 +232,141 @@ bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
return true;
}
- const std::string& listName = args[1];
+ std::string const& listName = args[1];
// expand the variable
std::string listString;
this->GetListString(listString, listName);
- if (!listString.empty() && !args.empty()) {
- listString += ";";
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then index is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
+
+ this->Makefile->AddDefinition(listName, listString.c_str());
+ return true;
+}
+
+bool cmListCommand::HandlePrependCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ // Skip if nothing to prepend.
+ if (args.size() < 3) {
+ return true;
}
- listString += cmJoin(cmMakeRange(args).advance(2), ";");
+
+ std::string const& listName = args[1];
+ // expand the variable
+ std::string listString;
+ this->GetListString(listString, listName);
+
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then `offset` is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString.insert(0,
+ cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
this->Makefile->AddDefinition(listName, listString.c_str());
return true;
}
+bool cmListCommand::HandlePopBackCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.pop_back();
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
+ assert(!ai->empty());
+ this->Makefile->AddDefinition(*ai, varArgsExpanded.back().c_str());
+ varArgsExpanded.pop_back();
+ }
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ this->Makefile->AddDefinition(listName,
+ cmJoin(varArgsExpanded, ";").c_str());
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
+bool cmListCommand::HandlePopFrontCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.erase(varArgsExpanded.begin());
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ auto vi = varArgsExpanded.begin();
+ for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
+ assert(!ai->empty());
+ this->Makefile->AddDefinition(*ai, vi->c_str());
+ }
+ varArgsExpanded.erase(varArgsExpanded.begin(), vi);
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ this->Makefile->AddDefinition(listName,
+ cmJoin(varArgsExpanded, ";").c_str());
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
{
if (args.size() != 4) {
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
index 76a985657..ea3d64399 100644
--- a/Source/cmListCommand.h
+++ b/Source/cmListCommand.h
@@ -35,6 +35,9 @@ protected:
bool HandleLengthCommand(std::vector<std::string> const& args);
bool HandleGetCommand(std::vector<std::string> const& args);
bool HandleAppendCommand(std::vector<std::string> const& args);
+ bool HandlePrependCommand(std::vector<std::string> const& args);
+ bool HandlePopBackCommand(std::vector<std::string> const& args);
+ bool HandlePopFrontCommand(std::vector<std::string> const& args);
bool HandleFindCommand(std::vector<std::string> const& args);
bool HandleInsertCommand(std::vector<std::string> const& args);
bool HandleJoinCommand(std::vector<std::string> const& args);
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index f85511964..df0d00c59 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -27,6 +27,8 @@ struct cmListFileParser
cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger, const char* filename);
~cmListFileParser();
+ cmListFileParser(const cmListFileParser&) = delete;
+ cmListFileParser& operator=(const cmListFileParser&) = delete;
void IssueFileOpenError(std::string const& text) const;
void IssueError(std::string const& text) const;
bool ParseFile();
@@ -190,12 +192,9 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
}
// Arguments.
- unsigned long lastLine;
unsigned long parenDepth = 0;
this->Separation = SeparationOkay;
- while (
- (static_cast<void>(lastLine = cmListFileLexer_GetCurrentLine(this->Lexer)),
- token = cmListFileLexer_Scan(this->Lexer))) {
+ while ((token = cmListFileLexer_Scan(this->Lexer))) {
if (token->type == cmListFileLexer_Token_Space ||
token->type == cmListFileLexer_Token_Newline) {
this->Separation = SeparationOkay;
@@ -250,7 +249,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
std::ostringstream error;
cmListFileContext lfc;
lfc.FilePath = this->FileName;
- lfc.Line = lastLine;
+ lfc.Line = line;
cmListFileBacktrace lfbt = this->Backtrace;
lfbt = lfbt.Push(lfc);
error << "Parse error. Function missing ending \")\". "
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index cd715188a..69751b62b 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -33,7 +33,7 @@ public:
this->info.CAPI = &cmStaticCAPI;
}
- ///! clean up any memory allocated by the plugin
+ //! clean up any memory allocated by the plugin
~cmLoadedCommand() override;
/**
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index f6962d160..fe5c8afe1 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -6,6 +6,7 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -34,6 +35,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <assert.h>
+#include <initializer_list>
#include <iterator>
#include <sstream>
#include <stdio.h>
@@ -51,25 +53,23 @@
// replaced in the form <var> with GetSafeDefinition(var).
// ${LANG} is replaced in the variable first with all enabled
// languages.
-static const char* ruleReplaceVars[] = {
- "CMAKE_${LANG}_COMPILER",
- "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
- "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
- "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
- "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
- "CMAKE_${LANG}_LINK_FLAGS",
- "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
- "CMAKE_${LANG}_ARCHIVE",
- "CMAKE_AR",
- "CMAKE_CURRENT_SOURCE_DIR",
- "CMAKE_CURRENT_BINARY_DIR",
- "CMAKE_RANLIB",
- "CMAKE_LINKER",
- "CMAKE_MT",
- "CMAKE_CUDA_HOST_COMPILER",
- "CMAKE_CUDA_HOST_LINK_LAUNCHER",
- "CMAKE_CL_SHOWINCLUDES_PREFIX"
-};
+static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
+ "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
+ "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
+ "CMAKE_${LANG}_LINK_FLAGS",
+ "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
+ "CMAKE_${LANG}_ARCHIVE",
+ "CMAKE_AR",
+ "CMAKE_CURRENT_SOURCE_DIR",
+ "CMAKE_CURRENT_BINARY_DIR",
+ "CMAKE_RANLIB",
+ "CMAKE_LINKER",
+ "CMAKE_MT",
+ "CMAKE_CUDA_HOST_COMPILER",
+ "CMAKE_CUDA_HOST_LINK_LAUNCHER",
+ "CMAKE_CL_SHOWINCLUDES_PREFIX" };
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
: cmOutputConverter(makefile->GetStateSnapshot())
@@ -151,15 +151,13 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
this->VariableMappings[compilerOptionSysroot] =
this->Makefile->GetSafeDefinition(compilerOptionSysroot);
- for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars);
- replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) {
- std::string actualReplace = *replaceIter;
- if (actualReplace.find("${LANG}") != std::string::npos) {
- cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
+ for (std::string replaceVar : ruleReplaceVars) {
+ if (replaceVar.find("${LANG}") != std::string::npos) {
+ cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
}
- this->VariableMappings[actualReplace] =
- this->Makefile->GetSafeDefinition(actualReplace);
+ this->VariableMappings[replaceVar] =
+ this->Makefile->GetSafeDefinition(replaceVar);
}
}
}
@@ -366,9 +364,8 @@ void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
void cmLocalGenerator::ProcessEvaluationFiles(
std::vector<std::string>& generatedFiles)
{
- std::vector<cmGeneratorExpressionEvaluationFile*> ef =
- this->Makefile->GetEvaluationFiles();
- for (cmGeneratorExpressionEvaluationFile* geef : ef) {
+ for (cmGeneratorExpressionEvaluationFile* geef :
+ this->Makefile->GetEvaluationFiles()) {
geef->Generate(this);
if (cmSystemTools::GetFatalErrorOccured()) {
return;
@@ -382,15 +379,15 @@ void cmLocalGenerator::ProcessEvaluationFiles(
std::back_inserter(intersection));
if (!intersection.empty()) {
cmSystemTools::Error("Files to be generated by multiple different "
- "commands: ",
- cmWrap('"', intersection, '"', " ").c_str());
+ "commands: " +
+ cmWrap('"', intersection, '"', " "));
return;
}
- generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
- std::vector<std::string>::iterator newIt =
- generatedFiles.end() - files.size();
- std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
+ cmAppend(generatedFiles, files);
+ std::inplace_merge(generatedFiles.begin(),
+ generatedFiles.end() - files.size(),
+ generatedFiles.end());
}
}
@@ -473,7 +470,7 @@ void cmLocalGenerator::GenerateInstallRules()
<< "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
<< " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
<< "endif()" << std::endl
- << "string(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
+ << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
<< "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
<< std::endl;
@@ -792,7 +789,7 @@ std::string cmLocalGenerator::GetIncludeFlags(
#endif
for (std::string const& i : includes) {
if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
- cmSystemTools::IsPathToFramework(i.c_str())) {
+ cmSystemTools::IsPathToFramework(i)) {
std::string frameworkDir = i;
frameworkDir += "/../";
frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
@@ -892,6 +889,32 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags,
}
}
this->AddCompilerRequirementFlag(flags, target, lang);
+
+ // Add compile flag for the MSVC compiler only.
+ cmMakefile* mf = this->GetMakefile();
+ if (const char* jmc =
+ mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
+
+ // Handle Just My Code debugging flags, /JMC.
+ // If the target is a Managed C++ one, /JMC is not compatible.
+ if (target->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Managed) {
+ // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
+ // to ON
+ if (char const* jmcExprGen =
+ target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(jmcExprGen);
+ std::string isJMCEnabled = cge->Evaluate(this, config);
+ if (cmSystemTools::IsOn(isJMCEnabled)) {
+ std::vector<std::string> optVec;
+ cmSystemTools::ExpandListArgument(jmc, optVec);
+ this->AppendCompileOptions(flags, optVec);
+ }
+ }
+ }
+ }
}
std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
@@ -1146,30 +1169,34 @@ void cmLocalGenerator::GetTargetFlags(
libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
CM_FALLTHROUGH;
case cmStateEnums::SHARED_LIBRARY: {
- linkFlags = this->Makefile->GetSafeDefinition(libraryLinkVariable);
- linkFlags += " ";
- if (!buildType.empty()) {
- std::string build = libraryLinkVariable;
- build += "_";
- build += buildType;
- linkFlags += this->Makefile->GetSafeDefinition(build);
+ if (linkLanguage != "Swift") {
+ linkFlags = this->Makefile->GetSafeDefinition(libraryLinkVariable);
linkFlags += " ";
- }
- if (this->Makefile->IsOn("WIN32") &&
- !(this->Makefile->IsOn("CYGWIN") || this->Makefile->IsOn("MINGW"))) {
- std::vector<cmSourceFile*> sources;
- target->GetSourceFiles(sources, buildType);
- std::string defFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
- for (cmSourceFile* sf : sources) {
- if (sf->GetExtension() == "def") {
- linkFlags += defFlag;
- linkFlags += this->ConvertToOutputFormat(
- cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL);
- linkFlags += " ";
+ if (!buildType.empty()) {
+ std::string build = libraryLinkVariable;
+ build += "_";
+ build += buildType;
+ linkFlags += this->Makefile->GetSafeDefinition(build);
+ linkFlags += " ";
+ }
+ if (this->Makefile->IsOn("WIN32") &&
+ !(this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"))) {
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, buildType);
+ std::string defFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ for (cmSourceFile* sf : sources) {
+ if (sf->GetExtension() == "def") {
+ linkFlags += defFlag;
+ linkFlags += this->ConvertToOutputFormat(
+ cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL);
+ linkFlags += " ";
+ }
}
}
}
+
const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
linkFlags += targetLinkFlags;
@@ -1184,6 +1211,7 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += " ";
}
}
+
std::vector<std::string> opts;
target->GetLinkOptions(opts, config, linkLanguage);
// LINK_OPTIONS are escaped.
@@ -1194,25 +1222,49 @@ void cmLocalGenerator::GetTargetFlags(
}
} break;
case cmStateEnums::EXECUTABLE: {
- linkFlags += this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
- linkFlags += " ";
- if (!buildType.empty()) {
- std::string build = "CMAKE_EXE_LINKER_FLAGS_";
- build += buildType;
- linkFlags += this->Makefile->GetSafeDefinition(build);
+ if (linkLanguage != "Swift") {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
linkFlags += " ";
+ if (!buildType.empty()) {
+ std::string build = "CMAKE_EXE_LINKER_FLAGS_";
+ build += buildType;
+ linkFlags += this->Makefile->GetSafeDefinition(build);
+ linkFlags += " ";
+ }
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ target->GetName());
+ return;
+ }
+
+ if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
+ linkFlags += " ";
+ } else {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
+ linkFlags += " ";
+ }
+
+ if (target->IsExecutableWithExports()) {
+ std::string exportFlagVar = "CMAKE_EXE_EXPORTS_";
+ exportFlagVar += linkLanguage;
+ exportFlagVar += "_FLAG";
+
+ linkFlags += this->Makefile->GetSafeDefinition(exportFlagVar);
+ linkFlags += " ";
+ }
}
- if (linkLanguage.empty()) {
- cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- target->GetName().c_str());
- return;
- }
+
this->AddLanguageFlagsForLinking(flags, target, linkLanguage, buildType);
if (pcli) {
this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
frameworkPath, linkPath);
}
+
if (cmSystemTools::IsOn(
this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
@@ -1220,23 +1272,6 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += this->Makefile->GetSafeDefinition(sFlagVar);
linkFlags += " ";
}
- if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
- linkFlags +=
- this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
- linkFlags += " ";
- } else {
- linkFlags +=
- this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
- linkFlags += " ";
- }
- if (target->IsExecutableWithExports()) {
- std::string exportFlagVar = "CMAKE_EXE_EXPORTS_";
- exportFlagVar += linkLanguage;
- exportFlagVar += "_FLAG";
-
- linkFlags += this->Makefile->GetSafeDefinition(exportFlagVar);
- linkFlags += " ";
- }
std::string cmp0065Flags =
this->GetLinkLibsCMP0065(linkLanguage, *target);
@@ -1259,6 +1294,7 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += " ";
}
}
+
std::vector<std::string> opts;
target->GetLinkOptions(opts, config, linkLanguage);
// LINK_OPTIONS are escaped.
@@ -1283,6 +1319,10 @@ void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
// Add language-specific flags.
this->AddLanguageFlags(flags, target, lang, config);
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
this->AddArchitectureFlags(flags, target, lang, config);
if (lang == "Fortran") {
@@ -1404,9 +1444,9 @@ void cmLocalGenerator::OutputLinkLibraries(
std::string linkLanguage = cli.GetLinkLanguage();
- std::string libPathFlag =
+ const std::string& libPathFlag =
this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
- std::string libPathTerminator =
+ const std::string& libPathTerminator =
this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
// Add standard libraries for this language.
@@ -1540,8 +1580,39 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
flagsVar += "_FLAGS";
this->AddConfigVariableFlags(flags, flagsVar, config);
- if (target->IsIPOEnabled(lang, config)) {
- this->AppendFeatureOptions(flags, lang, "IPO");
+ // Add MSVC runtime library flags. This is activated by the presence
+ // of a default selection whether or not it is overridden by a property.
+ const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
+ if (msvcRuntimeLibraryDefault && *msvcRuntimeLibraryDefault) {
+ const char* msvcRuntimeLibraryValue =
+ target->GetProperty("MSVC_RUNTIME_LIBRARY");
+ if (!msvcRuntimeLibraryValue) {
+ msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
+ }
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(msvcRuntimeLibraryValue);
+ std::string const msvcRuntimeLibrary =
+ cge->Evaluate(this, config, false, target);
+ if (!msvcRuntimeLibrary.empty()) {
+ if (const char* msvcRuntimeLibraryOptions =
+ this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
+ msvcRuntimeLibrary)) {
+ this->AppendCompileOptions(flags, msvcRuntimeLibraryOptions);
+ } else if ((this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
+ this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ // The compiler uses the MSVC ABI so it needs a known runtime library.
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "MSVC_RUNTIME_LIBRARY value '" +
+ msvcRuntimeLibrary + "' not known for this " +
+ lang + " compiler.");
+ }
+ }
}
}
@@ -1559,6 +1630,10 @@ void cmLocalGenerator::AddLanguageFlagsForLinking(
}
this->AddLanguageFlags(flags, target, lang, config);
+
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
}
cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
@@ -1852,7 +1927,9 @@ static void AddVisibilityCompileOption(std::string& flags,
strcmp(prop, "protected") != 0 && strcmp(prop, "internal") != 0) {
std::ostringstream e;
e << "Target " << target->GetName() << " uses unsupported value \"" << prop
- << "\" for " << flagDefine << ".";
+ << "\" for " << flagDefine << "."
+ << " The supported values are: default, hidden, protected, and "
+ "internal.";
cmSystemTools::Error(e.str());
return;
}
@@ -2263,11 +2340,8 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
dflag = df;
}
}
-
- std::set<std::string>::const_iterator defineIt = defines.begin();
- const std::set<std::string>::const_iterator defineEnd = defines.end();
const char* itemSeparator = definesString.empty() ? "" : " ";
- for (; defineIt != defineEnd; ++defineIt) {
+ for (std::string const& define : defines) {
// Append the definition with proper escaping.
std::string def = dflag;
if (this->GetState()->UseWatcomWMake()) {
@@ -2281,7 +2355,7 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
// command line without any escapes. However we still have to
// get the '$' and '#' characters through WMake as '$$' and
// '$#'.
- for (const char* c = defineIt->c_str(); *c; ++c) {
+ for (const char* c = define.c_str(); *c; ++c) {
if (*c == '$' || *c == '#') {
def += '$';
}
@@ -2290,11 +2364,11 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
} else {
// Make the definition appear properly on the command line. Use
// -DNAME="value" instead of -D"NAME=value" for historical reasons.
- std::string::size_type eq = defineIt->find("=");
- def += defineIt->substr(0, eq);
+ std::string::size_type eq = define.find('=');
+ def += define.substr(0, eq);
if (eq != std::string::npos) {
def += "=";
- def += this->EscapeForShell(defineIt->c_str() + eq + 1, true);
+ def += this->EscapeForShell(define.substr(eq + 1), true);
}
}
definesString += itemSeparator;
@@ -2851,7 +2925,7 @@ static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname)
+ const std::string& fname)
{
// Find the Info.plist template.
const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
@@ -2885,11 +2959,12 @@ 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.c_str(), fname, false, false, false);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
void cmLocalGenerator::GenerateFrameworkInfoPList(
- cmGeneratorTarget* target, const std::string& targetName, const char* fname)
+ cmGeneratorTarget* target, const std::string& targetName,
+ const std::string& fname)
{
// Find the Info.plist template.
const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
@@ -2919,5 +2994,5 @@ 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.c_str(), fname, false, false, false);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 9521ec5b8..f0c6806fb 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -76,13 +76,13 @@ public:
bool IsRootMakefile() const;
- ///! Get the makefile for this generator
+ //! Get the makefile for this generator
cmMakefile* GetMakefile() { return this->Makefile; }
- ///! Get the makefile for this generator, const version
+ //! Get the makefile for this generator, const version
const cmMakefile* GetMakefile() const { return this->Makefile; }
- ///! Get the GlobalGenerator this is associated with
+ //! Get the GlobalGenerator this is associated with
cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
const cmGlobalGenerator* GetGlobalGenerator() const
{
@@ -118,7 +118,7 @@ public:
void AddCompilerRequirementFlag(std::string& flags,
cmGeneratorTarget const* target,
const std::string& lang);
- ///! Append flags to a string.
+ //! Append flags to a string.
virtual void AppendFlags(std::string& flags,
const std::string& newFlags) const;
virtual void AppendFlags(std::string& flags, const char* newFlags) const;
@@ -131,7 +131,7 @@ public:
cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);
- ///! Get the include flags for the current makefile and language
+ //! Get the include flags for the current makefile and language
std::string GetIncludeFlags(const std::vector<std::string>& includes,
cmGeneratorTarget* target,
const std::string& lang,
@@ -340,14 +340,14 @@ public:
*/
void GenerateAppleInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname);
+ const std::string& fname);
/**
* Generate a macOS framework Info.plist file.
*/
void GenerateFrameworkInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname);
+ const std::string& fname);
/** Construct a comment for a custom command. */
std::string ConstructComment(cmCustomCommandGenerator const& ccg,
const char* default_comment = "");
@@ -403,7 +403,7 @@ public:
const std::string& prop);
protected:
- ///! put all the libraries for a target on into the given stream
+ //! put all the libraries for a target on into the given stream
void OutputLinkLibraries(cmComputeLinkInformation* pcli,
cmLinkLineComputer* linkLineComputer,
std::string& linkLibraries,
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
index 125e8b530..bf25f98ea 100644
--- a/Source/cmLocalGhsMultiGenerator.cxx
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -2,12 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalGhsMultiGenerator.h"
-#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGhsMultiTargetGenerator.h"
-#include "cmGlobalGhsMultiGenerator.h"
-#include "cmMakefile.h"
+#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+#include <algorithm>
+#include <utility>
cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
cmMakefile* mf)
@@ -15,9 +18,7 @@ cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
{
}
-cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
-{
-}
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator() = default;
std::string cmLocalGhsMultiGenerator::GetTargetDirectory(
cmGeneratorTarget const* target) const
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
index d5bec4200..b6ccd0815 100644
--- a/Source/cmLocalGhsMultiGenerator.h
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -5,7 +5,14 @@
#include "cmLocalGenerator.h"
-class cmGeneratedFileStream;
+#include <map>
+#include <string>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
/** \class cmLocalGhsMultiGenerator
* \brief Write Green Hills MULTI project files.
@@ -18,12 +25,12 @@ class cmLocalGhsMultiGenerator : public cmLocalGenerator
public:
cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
- virtual ~cmLocalGhsMultiGenerator();
+ ~cmLocalGhsMultiGenerator() override;
/**
* Generate the makefile for this directory.
*/
- virtual void Generate();
+ void Generate() override;
std::string GetTargetDirectory(
cmGeneratorTarget const* target) const override;
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 69656a286..81cafa321 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -14,6 +14,7 @@
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalNinjaGenerator.h"
@@ -69,7 +70,7 @@ void cmLocalNinjaGenerator::Generate()
this->WritePools(this->GetRulesFileStream());
- const std::string showIncludesPrefix =
+ const std::string& showIncludesPrefix =
this->GetMakefile()->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
if (!showIncludesPrefix.empty()) {
cmGlobalNinjaGenerator::WriteComment(this->GetRulesFileStream(),
@@ -79,25 +80,22 @@ void cmLocalNinjaGenerator::Generate()
}
}
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(target);
+ auto tg = cmNinjaTargetGenerator::New(target);
if (tg) {
tg->Generate();
// Add the target to "all" if required.
- if (!this->GetGlobalNinjaGenerator()->IsExcluded(
- this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
- target)) {
+ if (!this->GetGlobalNinjaGenerator()->IsExcluded(target)) {
this->GetGlobalNinjaGenerator()->AddDependencyToAll(target);
}
- delete tg;
}
}
this->WriteCustomCommandBuildStatements();
+ this->AdditionalCleanFiles();
}
// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
@@ -234,8 +232,8 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os)
os << " depth = " << jobs << std::endl;
os << std::endl;
} else {
- cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': ",
- pool.c_str());
+ cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " +
+ pool);
}
}
}
@@ -285,8 +283,7 @@ void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
void cmLocalNinjaGenerator::AppendCustomCommandDeps(
cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps)
{
- const std::vector<std::string>& deps = ccg.GetDepends();
- for (std::string const& i : deps) {
+ for (std::string const& i : ccg.GetDepends()) {
std::string dep;
if (this->GetRealDependency(i, this->GetConfigName(), dep)) {
ninjaDeps.push_back(
@@ -457,7 +454,8 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(
void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps)
{
- if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc)) {
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ if (gg->SeenCustomCommand(cc)) {
return;
}
@@ -465,13 +463,14 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
const std::vector<std::string>& outputs = ccg.GetOutputs();
const std::vector<std::string>& byproducts = ccg.GetByproducts();
- cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()), ninjaDeps;
bool symbolic = false;
- for (std::vector<std::string>::const_iterator o = outputs.begin();
- !symbolic && o != outputs.end(); ++o) {
- if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
- symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ for (std::string const& output : outputs) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+ if (sf->GetPropertyAsBool("SYMBOLIC")) {
+ symbolic = true;
+ break;
+ }
}
}
@@ -480,25 +479,29 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
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(),
- this->GetGlobalNinjaGenerator()->MapToNinjaPath());
+ gg->MapToNinjaPath());
std::transform(byproducts.begin(), byproducts.end(),
- ninjaOutputs.begin() + outputs.size(),
- this->GetGlobalNinjaGenerator()->MapToNinjaPath());
- this->AppendCustomCommandDeps(ccg, ninjaDeps);
+ ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath());
for (std::string const& ninjaOutput : ninjaOutputs) {
- this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(ninjaOutput);
+ gg->SeenCustomCommandOutput(ninjaOutput);
}
+ cmNinjaDeps ninjaDeps;
+ this->AppendCustomCommandDeps(ccg, ninjaDeps);
+
std::vector<std::string> cmdLines;
this->AppendCustomCommandLines(ccg, cmdLines);
if (cmdLines.empty()) {
- this->GetGlobalNinjaGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps,
- cmNinjaDeps(), orderOnlyDeps, cmNinjaVars());
+ 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->GetBuildFileStream(), build);
} else {
std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
// Hash full path to make unique.
@@ -506,10 +509,10 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
- this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
+ gg->WriteCustomCommandBuild(
this->BuildCommandLine(cmdLines, customStep),
this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
- cc->GetDepfile(), cc->GetUsesTerminal(),
+ cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(),
/*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
orderOnlyDeps);
}
@@ -601,3 +604,26 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher(
return launcher;
}
+
+void cmLocalNinjaGenerator::AdditionalCleanFiles()
+{
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> cleanFiles;
+ {
+ cmGeneratorExpression ge;
+ auto cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+ cleanFiles);
+ }
+ std::string const& binaryDir = this->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+ }
+ }
+}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index f772fb0a7..3a30bbb7b 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -105,6 +105,8 @@ private:
std::string const& customStep,
cmGeneratorTarget const* target) const;
+ void AdditionalCleanFiles();
+
std::string HomeRelativeOutputPath;
typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>>
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 7eb4a03d5..c392e9787 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -11,9 +11,11 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -22,6 +24,7 @@
#include "cmMakefile.h"
#include "cmMakefileTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -113,10 +116,9 @@ void cmLocalUnixMakefileGenerator3::Generate()
this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
// Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
cmGlobalUnixMakefileGenerator3* gg =
static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -152,8 +154,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
std::map<std::string, LocalObjectInfo>& localObjectFiles)
{
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
- for (cmGeneratorTarget* gt : targets) {
+ for (cmGeneratorTarget* gt : this->GetGeneratorTargets()) {
if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -351,9 +352,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
// for each target we just provide a rule to cd up to the top and do a make
// on the target
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
std::string localName;
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if ((target->GetType() == cmStateEnums::EXECUTABLE) ||
(target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
(target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
@@ -501,8 +501,11 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
{
// Make sure there is a target.
if (target.empty()) {
- cmSystemTools::Error("No target for WriteMakeRule! called with comment: ",
- comment);
+ std::string err("No target for WriteMakeRule! called with comment: ");
+ if (comment) {
+ err += comment;
+ }
+ cmSystemTools::Error(err);
return;
}
@@ -859,7 +862,7 @@ void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
// Add a dependency on the rule file itself unless an option to skip
// it is specifically enabled by the user or project.
if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
- depends.insert(depends.end(), ruleFiles.begin(), ruleFiles.end());
+ cmAppend(depends, ruleFiles);
}
}
@@ -1034,11 +1037,11 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
this->CreateCDCommand(commands1, dir, relative);
// push back the custom commands
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
}
void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
- std::vector<std::string>& commands, const std::vector<std::string>& files,
+ std::vector<std::string>& commands, const std::set<std::string>& files,
cmGeneratorTarget* target, const char* filename)
{
std::string currentBinDir = this->GetCurrentBinaryDirectory();
@@ -1054,7 +1057,7 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
cmsys::ofstream fout(cleanfilePath.c_str());
if (!fout) {
- cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
+ cmSystemTools::Error("Could not create " + cleanfilePath);
}
if (!files.empty()) {
fout << "file(REMOVE_RECURSE\n";
@@ -1090,6 +1093,56 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
}
}
+void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
+ std::vector<std::string>& commands)
+{
+ std::vector<std::string> cleanFiles;
+ // Look for additional files registered for cleaning in this directory.
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+ cleanFiles);
+ }
+ if (cleanFiles.empty()) {
+ return;
+ }
+
+ cmLocalGenerator* rootLG =
+ this->GetGlobalGenerator()->GetLocalGenerators().at(0);
+ std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
+ std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
+ std::string cleanfile = currentBinaryDir;
+ cleanfile += "/CMakeFiles/cmake_directory_clean.cmake";
+ // Write clean script
+ {
+ std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
+ cmsys::ofstream fout(cleanfilePath.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not create " + cleanfilePath);
+ return;
+ }
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& cfl : cleanFiles) {
+ std::string fc = rootLG->MaybeConvertToRelativePath(
+ binaryDir, cmSystemTools::CollapseFullPath(cfl, currentBinaryDir));
+ fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n";
+ }
+ fout << ")\n";
+ }
+ // Create command
+ {
+ std::string remove = "$(CMAKE_COMMAND) -P ";
+ remove += this->ConvertToOutputFormat(
+ rootLG->MaybeConvertToRelativePath(binaryDir, cleanfile),
+ cmOutputConverter::SHELL);
+ commands.push_back(std::move(remove));
+ }
+}
+
void cmLocalUnixMakefileGenerator3::AppendEcho(
std::vector<std::string>& commands, std::string const& text, EchoColor color,
EchoProgress const* progress)
@@ -1263,21 +1316,20 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// Check if any multiple output pairs have a missing file.
this->CheckMultipleOutputs(verbose);
- std::string dir = cmSystemTools::GetFilenamePath(tgtInfo);
- std::string internalDependFile = dir + "/depend.internal";
- std::string dependFile = dir + "/depend.make";
+ 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;
- cmFileTimeComparison* ftc =
- this->GlobalGenerator->GetCMakeInstance()->GetFileComparison();
+ cmFileTimeCache* ftc =
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
{
int result;
- if (!ftc->FileTimeCompare(internalDependFile, tgtInfo, &result) ||
- result < 0) {
+ if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
if (verbose) {
std::ostringstream msg;
msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
@@ -1291,12 +1343,12 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// 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 = this->GetCurrentBinaryDirectory();
- dirInfoFile += "/CMakeFiles";
- dirInfoFile += "/CMakeDirectoryInformation.cmake";
{
+ std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+ dirInfoFile += "/CMakeFiles";
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
int result;
- if (!ftc->FileTimeCompare(internalDependFile, dirInfoFile, &result) ||
+ if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
result < 0) {
if (verbose) {
std::ostringstream msg;
@@ -1312,12 +1364,12 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// 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.
- std::map<std::string, cmDepends::DependencyVector> validDependencies;
+ cmDepends::DependencyMap validDependencies;
bool needRescanDependencies = false;
if (!needRescanDirInfo) {
cmDependsC checker;
checker.SetVerbose(verbose);
- checker.SetFileComparison(ftc);
+ 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.
@@ -1334,7 +1386,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
// The dependencies must be regenerated.
- std::string targetName = cmSystemTools::GetFilenameName(dir);
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
targetName = targetName.substr(0, targetName.length() - 4);
std::string message = "Scanning dependencies of target ";
message += targetName;
@@ -1342,7 +1394,8 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
cmsysTerminal_Color_ForegroundBold,
message.c_str(), true, color);
- return this->ScanDependencies(dir, validDependencies);
+ return this->ScanDependencies(targetDir, dependFile, internalDependFile,
+ validDependencies);
}
// The dependencies are already up-to-date.
@@ -1350,17 +1403,20 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
}
bool cmLocalUnixMakefileGenerator3::ScanDependencies(
- const std::string& targetDir,
- std::map<std::string, cmDepends::DependencyVector>& validDeps)
+ std::string const& targetDir, std::string const& dependFile,
+ std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
{
// Read the directory information file.
cmMakefile* mf = this->Makefile;
bool haveDirectoryInfo = false;
- std::string dirInfoFile = this->GetCurrentBinaryDirectory();
- dirInfoFile += "/CMakeFiles";
- dirInfoFile += "/CMakeDirectoryInformation.cmake";
- if (mf->ReadListFile(dirInfoFile) && !cmSystemTools::GetErrorOccuredFlag()) {
- haveDirectoryInfo = true;
+ {
+ std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+ dirInfoFile += "/CMakeFiles";
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
+ if (mf->ReadListFile(dirInfoFile) &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ haveDirectoryInfo = true;
+ }
}
// Lookup useful directory information.
@@ -1389,10 +1445,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
// Open the make depends file. This should be copy-if-different
// because the make tool may try to reload it needlessly otherwise.
- std::string ruleFileNameFull = targetDir;
- ruleFileNameFull += "/depend.make";
cmGeneratedFileStream ruleFileStream(
- ruleFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+ dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
ruleFileStream.SetCopyIfDifferent(true);
if (!ruleFileStream) {
return false;
@@ -1401,11 +1455,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
// 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.
- std::string internalRuleFileNameFull = targetDir;
- internalRuleFileNameFull += "/depend.internal";
cmGeneratedFileStream internalRuleFileStream(
- internalRuleFileNameFull, false,
- this->GlobalGenerator->GetMakefileEncoding());
+ internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
if (!internalRuleFileStream) {
return false;
}
@@ -1414,39 +1465,35 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
this->WriteDisclaimer(internalRuleFileStream);
// for each language we need to scan, scan it
- std::string const& langStr =
- mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES");
std::vector<std::string> langs;
- cmSystemTools::ExpandListArgument(langStr, langs);
+ cmSystemTools::ExpandListArgument(
+ mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"), langs);
for (std::string const& lang : langs) {
// construct the checker
// Create the scanner for this language
- cmDepends* scanner = nullptr;
+ std::unique_ptr<cmDepends> scanner;
if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
lang == "CUDA") {
// TODO: Handle RC (resource files) dependencies correctly.
- scanner = new cmDependsC(this, targetDir, lang, &validDeps);
+ scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
}
#ifdef CMAKE_BUILD_WITH_CMAKE
else if (lang == "Fortran") {
ruleFileStream << "# Note that incremental build could trigger "
<< "a call to cmake_copy_f90_mod on each re-build\n";
- scanner = new cmDependsFortran(this);
+ scanner = cm::make_unique<cmDependsFortran>(this);
} else if (lang == "Java") {
- scanner = new cmDependsJava();
+ scanner = cm::make_unique<cmDependsJava>();
}
#endif
if (scanner) {
scanner->SetLocalGenerator(this);
- scanner->SetFileComparison(
- this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
+ scanner->SetFileTimeCache(
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
scanner->SetLanguage(lang);
scanner->SetTargetDirectory(targetDir);
scanner->Write(ruleFileStream, internalRuleFileStream);
-
- // free the scanner for this language
- delete scanner;
}
}
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index ced2dbd46..c8e4b0e97 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -143,8 +143,7 @@ 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 std::map<std::string, cmDepends::DependencyVector>
+ struct ImplicitDependFileMap : public cmDepends::DependencyMap
{
};
struct ImplicitDependLanguageMap
@@ -225,14 +224,16 @@ protected:
bool echo_comment = false,
std::ostream* content = nullptr);
void AppendCleanCommand(std::vector<std::string>& commands,
- const std::vector<std::string>& files,
+ const std::set<std::string>& files,
cmGeneratorTarget* target,
const char* filename = nullptr);
+ void AppendDirectoryCleanCommand(std::vector<std::string>& commands);
// Helper methods for dependency updates.
- bool ScanDependencies(
- const std::string& targetDir,
- std::map<std::string, cmDepends::DependencyVector>& validDeps);
+ bool ScanDependencies(std::string const& targetDir,
+ std::string const& dependFile,
+ std::string const& internalDependFile,
+ cmDepends::DependencyMap& validDeps);
void CheckMultipleOutputs(bool verbose);
private:
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
index a4150b94d..5c6400e9f 100644
--- a/Source/cmLocalVisualStudio10Generator.h
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -21,7 +21,7 @@ class cmMakefile;
class cmLocalVisualStudio10Generator : public cmLocalVisualStudio7Generator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
virtual ~cmLocalVisualStudio10Generator();
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 7019552c3..7ba347177 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalVisualStudio7Generator.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio7Generator.h"
@@ -118,8 +119,8 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles()
// If not an in source build, then create the output directory
if (this->GetCurrentBinaryDirectory() != this->GetSourceDirectory()) {
if (!cmSystemTools::MakeDirectory(this->GetCurrentBinaryDirectory())) {
- cmSystemTools::Error("Error creating directory ",
- this->GetCurrentBinaryDirectory().c_str());
+ cmSystemTools::Error("Error creating directory " +
+ this->GetCurrentBinaryDirectory());
}
}
@@ -283,7 +284,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
file->GetFullPath();
return file;
} else {
- cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
+ cmSystemTools::Error("Error adding rule for " + makefileIn);
return nullptr;
}
}
@@ -293,9 +294,8 @@ void cmLocalVisualStudio7Generator::WriteConfigurations(
const std::string& libName, cmGeneratorTarget* target)
{
fout << "\t<Configurations>\n";
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i) {
- this->WriteConfiguration(fout, i->c_str(), libName, target);
+ for (std::string const& config : configs) {
+ this->WriteConfiguration(fout, config.c_str(), libName, target);
}
fout << "\t</Configurations>\n";
}
@@ -569,9 +569,8 @@ public:
void Finish() { this->Stream << (this->First ? "" : "\"") << "/>\n"; }
void Write(std::vector<cmCustomCommand> const& ccs)
{
- for (std::vector<cmCustomCommand>::const_iterator ci = ccs.begin();
- ci != ccs.end(); ++ci) {
- this->Write(*ci);
+ for (cmCustomCommand const& command : ccs) {
+ this->Write(command);
}
}
void Write(cmCustomCommand const& cc)
@@ -656,21 +655,14 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
: target->GetLinkerLanguage(configName));
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- target->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ target->GetName());
return;
}
langForClCompile = linkLanguage;
if (langForClCompile == "C" || langForClCompile == "CXX" ||
langForClCompile == "Fortran") {
- std::string baseFlagVar = "CMAKE_";
- baseFlagVar += langForClCompile;
- baseFlagVar += "_FLAGS";
- flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
- std::string flagVar =
- baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
- flags += " ";
- flags += this->Makefile->GetRequiredDefinition(flagVar);
+ this->AddLanguageFlags(flags, target, langForClCompile, configName);
}
// set the correct language
if (linkLanguage == "C") {
@@ -897,10 +889,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
target->GetManifests(manifest_srcs, configName);
if (!manifest_srcs.empty()) {
fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
- for (std::vector<cmSourceFile const*>::const_iterator mi =
- manifest_srcs.begin();
- mi != manifest_srcs.end(); ++mi) {
- std::string m = (*mi)->GetFullPath();
+ for (cmSourceFile const* manifest : manifest_srcs) {
+ std::string m = manifest->GetFullPath();
fout << this->ConvertToXMLOutputPath(m.c_str()) << ";";
}
fout << "\"";
@@ -931,7 +921,7 @@ std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
std::string extraLinkOptionsBuildTypeDef =
rootLinkerFlags + "_" + configTypeUpper;
- std::string extraLinkOptionsBuildType =
+ const std::string& extraLinkOptionsBuildType =
this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
return extraLinkOptionsBuildType;
@@ -947,21 +937,18 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
std::string extraLinkOptions;
if (target->GetType() == cmStateEnums::EXECUTABLE) {
extraLinkOptions =
- this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") +
- std::string(" ") +
+ this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") + " " +
GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
}
if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
extraLinkOptions =
this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
- std::string(" ") +
- GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
+ " " + GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
}
if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
extraLinkOptions =
this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
- std::string(" ") +
- GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
+ " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
}
const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
@@ -1050,13 +1037,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
}
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
- targetNameImport, targetNamePDB, configName);
+ cmGeneratorTarget::Names targetNames =
+ target->GetLibraryNames(configName);
// Compute the link library and directory information.
cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1092,7 +1074,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetDirectory(configName);
temp += "/";
- temp += targetNameFull;
+ temp += targetNames.Output;
fout << "\t\t\t\tOutputFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
this->WriteTargetVersionAttribute(fout, target);
@@ -1102,7 +1084,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetPDBDirectory(configName);
temp += "/";
- temp += targetNamePDB;
+ temp += targetNames.PDB;
fout << "\t\t\t\tProgramDatabaseFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
if (targetOptions.IsDebug()) {
@@ -1125,7 +1107,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
temp =
target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
temp += "/";
- temp += targetNameImport;
+ temp += targetNames.ImportLibrary;
fout << "\t\t\t\tImportLibrary=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"";
if (this->FortranProject) {
@@ -1134,12 +1116,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "/>\n";
} break;
case cmStateEnums::EXECUTABLE: {
- std::string targetName;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetExecutableNames(targetName, targetNameFull, targetNameImport,
- targetNamePDB, configName);
+ cmGeneratorTarget::Names targetNames =
+ target->GetExecutableNames(configName);
// Compute the link library and directory information.
cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1177,7 +1155,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetDirectory(configName);
temp += "/";
- temp += targetNameFull;
+ temp += targetNames.Output;
fout << "\t\t\t\tOutputFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
this->WriteTargetVersionAttribute(fout, target);
@@ -1187,8 +1165,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
std::string path = this->ConvertToXMLOutputPathSingle(
target->GetPDBDirectory(configName).c_str());
- fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB
- << "\"\n";
+ fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
+ << targetNames.PDB << "\"\n";
if (targetOptions.IsDebug()) {
fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
}
@@ -1223,7 +1201,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
temp =
target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
temp += "/";
- temp += targetNameImport;
+ temp += targetNames.ImportLibrary;
fout << "\t\t\t\tImportLibrary=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n";
break;
@@ -1303,14 +1281,14 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
{
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
std::string currentBinDir = lg->GetCurrentBinaryDirectory();
- for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) {
- if (l->IsPath) {
+ for (auto const& lib : libs) {
+ if (lib.IsPath) {
std::string rel =
- lg->MaybeConvertToRelativePath(currentBinDir, l->Value.c_str());
+ lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.c_str());
fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
- } else if (!l->Target ||
- l->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
- fout << l->Value << " ";
+ } else if (!lib.Target ||
+ lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ fout << lib.Value << " ";
}
}
}
@@ -1328,10 +1306,9 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
gt->GetExternalObjects(objs, configName);
const char* sep = isep ? isep : "";
- for (std::vector<cmSourceFile const*>::const_iterator i = objs.begin();
- i != objs.end(); ++i) {
- if (!(*i)->GetObjectLibrary().empty()) {
- std::string const& objFile = (*i)->GetFullPath();
+ for (cmSourceFile const* obj : objs) {
+ if (!obj->GetObjectLibrary().empty()) {
+ std::string const& objFile = obj->GetFullPath();
std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile);
fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
sep = " ";
@@ -1344,10 +1321,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories(
{
const char* comma = "";
std::string currentBinDir = this->GetCurrentBinaryDirectory();
- for (std::vector<std::string>::const_iterator d = dirs.begin();
- d != dirs.end(); ++d) {
+ for (std::string dir : dirs) {
// Remove any trailing slash and skip empty paths.
- std::string dir = *d;
if (dir.back() == '/') {
dir = dir.substr(0, dir.size() - 1);
}
@@ -1483,9 +1458,8 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
// Compute per-source, per-config information.
size_t ci = 0;
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i, ++ci) {
- std::string configUpper = cmSystemTools::UpperCase(*i);
+ for (std::string const& config : configs) {
+ std::string configUpper = cmSystemTools::UpperCase(config);
cmLVS7GFileConfig fc;
std::string lang =
@@ -1498,7 +1472,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
lang = sourceLang;
}
- cmGeneratorExpressionInterpreter genexInterpreter(lg, *i, gt, lang);
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gt, lang);
bool needfc = false;
if (!objectName.empty()) {
@@ -1564,7 +1538,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
}
- const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
+ const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str());
// If HEADER_FILE_ONLY is set, we must suppress this generation in
// the project file
fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
@@ -1589,8 +1563,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
if (needfc) {
- this->FileConfigMap[*i] = fc;
+ this->FileConfigMap[config] = fc;
}
+ ++ci;
}
}
@@ -1654,16 +1629,14 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
}
// Loop through each source in the source group.
- for (std::vector<const cmSourceFile*>::const_iterator sf =
- sourceFiles.begin();
- sf != sourceFiles.end(); ++sf) {
- std::string source = (*sf)->GetFullPath();
+ for (const cmSourceFile* sf : sourceFiles) {
+ std::string source = sf->GetFullPath();
if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// Look up the source kind and configs.
std::map<cmSourceFile const*, size_t>::const_iterator map_it =
- sources.Index.find(*sf);
+ sources.Index.find(sf);
// The map entry must exist because we populated it earlier.
assert(map_it != sources.Index.end());
cmGeneratorTarget::AllConfigSource const& acs =
@@ -1676,7 +1649,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
// Tell MS-Dev what the source is. If the compiler knows how to
// build it, then it will.
fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
- if (cmCustomCommand const* command = (*sf)->GetCustomCommand()) {
+ if (cmCustomCommand const* command = sf->GetCustomCommand()) {
this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo);
} else if (!fcinfo.FileConfigMap.empty()) {
const char* aCompilerTool = "VCCLCompilerTool";
@@ -1684,8 +1657,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
if (this->FortranProject) {
aCompilerTool = "VFFortranCompilerTool";
}
- std::string const& lang = (*sf)->GetLanguage();
- std::string ext = (*sf)->GetExtension();
+ std::string const& lang = sf->GetLanguage();
+ std::string ext = sf->GetExtension();
ext = cmSystemTools::LowerCase(ext);
if (ext == "idl") {
aCompilerTool = "VCMIDLTool";
@@ -1713,12 +1686,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
aCompilerTool = "VCCustomBuildTool";
}
- for (std::map<std::string, cmLVS7GFileConfig>::const_iterator fci =
- fcinfo.FileConfigMap.begin();
- fci != fcinfo.FileConfigMap.end(); ++fci) {
- cmLVS7GFileConfig const& fc = fci->second;
+ for (auto const& fci : fcinfo.FileConfigMap) {
+ cmLVS7GFileConfig const& fc = fci.second;
fout << "\t\t\t\t<FileConfiguration\n"
- << "\t\t\t\t\tName=\"" << fci->first << "|"
+ << "\t\t\t\t\tName=\"" << fci.first << "|"
<< gg->GetPlatformName() << "\"";
if (fc.ExcludedFromBuild) {
fout << " ExcludedFromBuild=\"true\"";
@@ -1741,7 +1712,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
fileOptions.AddDefines(fc.CompileDefsConfig);
// validate source level include directories
std::vector<std::string> includes;
- this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf);
+ this->AppendIncludeDirectories(includes, fc.IncludeDirs, *sf);
fileOptions.AddIncludes(includes);
fileOptions.OutputFlagMap(fout, 5);
fileOptions.OutputAdditionalIncludeDirectories(
@@ -1794,12 +1765,11 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
if (this->FortranProject) {
customTool = "VFCustomBuildTool";
}
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i) {
- cmCustomCommandGenerator ccg(command, *i, this);
- cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[*i];
+ for (std::string const& config : configs) {
+ cmCustomCommandGenerator ccg(command, config, this);
+ cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[config];
fout << "\t\t\t\t<FileConfiguration\n";
- fout << "\t\t\t\t\tName=\"" << *i << "|" << gg->GetPlatformName()
+ fout << "\t\t\t\t\tName=\"" << config << "|" << gg->GetPlatformName()
<< "\">\n";
if (!fc.CompileFlags.empty()) {
fout << "\t\t\t\t\t<Tool\n"
@@ -1811,7 +1781,7 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
std::string comment = this->ConstructComment(ccg);
std::string script = this->ConstructScript(ccg);
if (this->FortranProject) {
- cmSystemTools::ReplaceString(script, "$(Configuration)", i->c_str());
+ cmSystemTools::ReplaceString(script, "$(Configuration)", config.c_str());
}
/* clang-format off */
fout << "\t\t\t\t\t<Tool\n"
@@ -1832,12 +1802,10 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
fout << this->ConvertToXMLOutputPath(source);
} else {
// Write out the dependencies for the rule.
- for (std::vector<std::string>::const_iterator d =
- ccg.GetDepends().begin();
- d != ccg.GetDepends().end(); ++d) {
+ for (std::string const& d : ccg.GetDepends()) {
// Get the real name of the dependency in case it is a CMake target.
std::string dep;
- if (this->GetRealDependency(d->c_str(), i->c_str(), dep)) {
+ if (this->GetRealDependency(d.c_str(), config.c_str(), dep)) {
fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";";
}
}
@@ -1849,10 +1817,8 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
} else {
// Write a rule for the output generated by this command.
const char* sep = "";
- for (std::vector<std::string>::const_iterator o =
- ccg.GetOutputs().begin();
- o != ccg.GetOutputs().end(); ++o) {
- fout << sep << this->ConvertToXMLOutputPathSingle(o->c_str());
+ for (std::string const& output : ccg.GetOutputs()) {
+ fout << sep << this->ConvertToXMLOutputPathSingle(output.c_str());
sep = ";";
}
}
@@ -2063,16 +2029,14 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter(
{
fout << "\t<Globals>\n";
- std::vector<std::string> const& props = target->GetPropertyKeys();
- for (std::vector<std::string>::const_iterator i = props.begin();
- i != props.end(); ++i) {
- if (i->find("VS_GLOBAL_") == 0) {
- std::string name = i->substr(10);
+ for (std::string const& key : target->GetPropertyKeys()) {
+ if (key.find("VS_GLOBAL_") == 0) {
+ std::string name = key.substr(10);
if (!name.empty()) {
/* clang-format off */
fout << "\t\t<Global\n"
<< "\t\t\tName=\"" << name << "\"\n"
- << "\t\t\tValue=\"" << target->GetProperty(*i) << "\"\n"
+ << "\t\t\tValue=\"" << target->GetProperty(key) << "\"\n"
<< "\t\t/>\n";
/* clang-format on */
}
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index b093e6fc9..ce8eceb7e 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -43,7 +43,7 @@ public:
class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
virtual ~cmLocalVisualStudio7Generator();
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 660729c3a..f3f2042ec 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalVisualStudioGenerator.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
index 5c22dcf68..42de20b47 100644
--- a/Source/cmLocalXCodeGenerator.h
+++ b/Source/cmLocalXCodeGenerator.h
@@ -24,7 +24,7 @@ class cmSourceFile;
class cmLocalXCodeGenerator : public cmLocalGenerator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
~cmLocalXCodeGenerator() override;
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 7279d5fcf..e9c6aea73 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -10,6 +10,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmSystemTools.h"
@@ -211,7 +212,7 @@ bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
// create a function blocker
cmMacroFunctionBlocker* f = new cmMacroFunctionBlocker();
- f->Args.insert(f->Args.end(), args.begin(), args.end());
+ cmAppend(f->Args, args);
this->Makefile->AddFunctionBlocker(f);
return true;
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 27351226f..e0f69cb4b 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -31,6 +31,7 @@
#include "cmInstallSubdirectoryGenerator.h"
#include "cmListFileCache.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
@@ -292,13 +293,14 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
bool trace = trace_only_this_files.empty();
if (!trace) {
- for (std::vector<std::string>::const_iterator i =
- trace_only_this_files.begin();
- !trace && i != trace_only_this_files.end(); ++i) {
- std::string::size_type const pos = full_path.rfind(*i);
+ for (std::string const& file : trace_only_this_files) {
+ std::string::size_type const pos = full_path.rfind(file);
trace = (pos != std::string::npos) &&
- ((pos + i->size()) == full_path.size()) &&
- (only_filename == cmSystemTools::GetFilenameName(*i));
+ ((pos + file.size()) == full_path.size()) &&
+ (only_filename == cmSystemTools::GetFilenameName(file));
+ if (trace) {
+ break;
+ }
}
// Do nothing if current file wasn't requested for trace...
if (!trace) {
@@ -347,6 +349,9 @@ public:
this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
}
+ cmMakefileCall(const cmMakefileCall&) = delete;
+ cmMakefileCall& operator=(const cmMakefileCall&) = delete;
+
private:
cmMakefile* Makefile;
};
@@ -438,6 +443,9 @@ public:
~IncludeScope();
void Quiet() { this->ReportError = false; }
+ IncludeScope(const IncludeScope&) = delete;
+ IncludeScope& operator=(const IncludeScope&) = delete;
+
private:
cmMakefile* Makefile;
bool NoPolicyScope;
@@ -605,6 +613,9 @@ public:
void Quiet() { this->ReportError = false; }
+ ListFileScope(const ListFileScope&) = delete;
+ ListFileScope& operator=(const ListFileScope&) = delete;
+
private:
cmMakefile* Makefile;
bool ReportError;
@@ -803,11 +814,11 @@ void cmMakefile::AddCustomCommandToTarget(
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile, bool command_expand_lists,
- ObjectLibraryCommands objLibraryCommands)
+ bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+ bool command_expand_lists, ObjectLibraryCommands objLibraryCommands)
{
// Find the target to which to add the custom command.
- cmTargets::iterator ti = this->Targets.find(target);
+ cmTargetMap::iterator ti = this->Targets.find(target);
if (ti == this->Targets.end()) {
MessageType messageType = MessageType::AUTHOR_WARNING;
@@ -879,6 +890,7 @@ void cmMakefile::AddCustomCommandToTarget(
cc.SetUsesTerminal(uses_terminal);
cc.SetCommandExpandLists(command_expand_lists);
cc.SetDepfile(depfile);
+ cc.SetJobPool(job_pool);
switch (type) {
case cmTarget::PRE_BUILD:
t.AddPreBuildCommand(cc);
@@ -898,7 +910,8 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
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)
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
{
// Make sure there is at least one output.
if (outputs.empty()) {
@@ -949,9 +962,8 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
if (file && file->GetCustomCommand() && !replace) {
// The rule file already exists.
if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
- cmSystemTools::Error("Attempt to add a custom rule to output \"",
- outName.c_str(),
- "\" which already has a custom rule.");
+ cmSystemTools::Error("Attempt to add a custom rule to output \"" +
+ outName + "\" which already has a custom rule.");
}
return file;
}
@@ -993,6 +1005,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
cc->SetUsesTerminal(uses_terminal);
cc->SetCommandExpandLists(command_expand_lists);
cc->SetDepfile(depfile);
+ cc->SetJobPool(job_pool);
file->SetCustomCommand(cc);
this->UpdateOutputToSourceMap(outputs, file);
}
@@ -1030,7 +1043,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
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& depfile, const std::string& job_pool)
{
std::vector<std::string> outputs;
outputs.push_back(output);
@@ -1038,7 +1051,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
return this->AddCustomCommandToOutput(
outputs, no_byproducts, depends, main_dependency, commandLines, comment,
workingDir, replace, escapeOldStyle, uses_terminal, command_expand_lists,
- depfile);
+ depfile, job_pool);
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1086,13 +1099,13 @@ void cmMakefile::AddCustomCommandOldStyle(
// then add the source to the target to make sure the rule is
// included.
if (sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) {
- cmTargets::iterator ti = this->Targets.find(target);
+ cmTargetMap::iterator ti = this->Targets.find(target);
if (ti != this->Targets.end()) {
ti->second.AddSource(sf->GetFullPath());
} else {
cmSystemTools::Error("Attempt to add a custom rule to a target "
- "that does not exist yet for target ",
- target.c_str());
+ "that does not exist yet for target " +
+ target);
return;
}
}
@@ -1132,13 +1145,14 @@ cmTarget* cmMakefile::AddUtilityCommand(
const std::string& utilityName, TargetOrigin origin, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal, bool command_expand_lists)
+ const char* comment, bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
{
std::vector<std::string> no_byproducts;
- return this->AddUtilityCommand(utilityName, origin, excludeFromAll,
- workingDirectory, no_byproducts, depends,
- commandLines, escapeOldStyle, comment,
- uses_terminal, command_expand_lists);
+ return this->AddUtilityCommand(
+ utilityName, origin, excludeFromAll, workingDirectory, no_byproducts,
+ depends, commandLines, escapeOldStyle, comment, uses_terminal,
+ command_expand_lists, job_pool);
}
cmTarget* cmMakefile::AddUtilityCommand(
@@ -1146,12 +1160,13 @@ cmTarget* cmMakefile::AddUtilityCommand(
const char* workingDirectory, 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 char* comment, bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
{
// Create a target instance for this utility.
cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
target->SetIsGeneratorProvided(origin == TargetOrigin::Generator);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
if (!comment) {
@@ -1172,15 +1187,14 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->AddCustomCommandToOutput(
forced, byproducts, depends, no_main_dependency, commandLines, comment,
workingDirectory, no_replace, escapeOldStyle, uses_terminal,
- command_expand_lists);
+ command_expand_lists, /*depfile=*/"", job_pool);
cmSourceFile* sf = target->AddSourceCMP0049(force);
// 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.c_str());
+ cmSystemTools::Error("Could not get source file entry for " + force);
}
// Always create the byproduct sources and mark them generated.
@@ -1496,6 +1510,9 @@ public:
void Quiet() { this->ReportError = false; }
+ BuildsystemFileScope(const BuildsystemFileScope&) = delete;
+ BuildsystemFileScope& operator=(const BuildsystemFileScope&) = delete;
+
private:
cmMakefile* Makefile;
cmGlobalGenerator* GG;
@@ -1587,6 +1604,16 @@ void cmMakefile::Configure()
}
// if no project command is found, add one
if (!hasProject) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "No project() command is present. The top-level CMakeLists.txt "
+ "file must contain a literal, direct call to the project() command. "
+ "Add a line of code such as\n"
+ " project(ProjectName)\n"
+ "near the top of the file, but after cmake_minimum_required().\n"
+ "CMake is pretending there is a \"project(Project)\" command on "
+ "the first line.",
+ this->Backtrace);
cmListFileFunction project;
project.Name.Lower = "project";
project.Arguments.emplace_back("Project", cmListFileArgument::Unquoted,
@@ -1689,7 +1716,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot);
this->GetGlobalGenerator()->AddMakefile(subMf);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
@@ -1848,10 +1875,8 @@ void cmMakefile::CheckForUnusedVariables() const
if (!this->WarnUnused) {
return;
}
- const std::vector<std::string>& unused = this->StateSnapshot.UnusedKeys();
- std::vector<std::string>::const_iterator it = unused.begin();
- for (; it != unused.end(); ++it) {
- this->LogUnused("out of scope", *it);
+ for (const std::string& key : this->StateSnapshot.UnusedKeys()) {
+ this->LogUnused("out of scope", key);
}
}
@@ -1985,7 +2010,9 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname,
// over changes in CMakeLists.txt, making the information stale and
// hence useless.
target->ClearDependencyInformation(*this);
- if (excludeFromAll) {
+ if (excludeFromAll ||
+ (type != cmStateEnums::INTERFACE_LIBRARY &&
+ this->GetPropertyAsBool("EXCLUDE_FROM_ALL"))) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
target->AddSources(srcs);
@@ -1998,7 +2025,7 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
bool excludeFromAll)
{
cmTarget* target = this->AddNewTarget(cmStateEnums::EXECUTABLE, exeName);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
target->AddSources(srcs);
@@ -2009,10 +2036,9 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
const std::string& name)
{
- cmTargets::iterator it =
+ cmTargetMap::iterator it =
this->Targets
- .insert(cmTargets::value_type(
- name, cmTarget(name, type, cmTarget::VisibilityNormal, this)))
+ .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
.first;
this->GetGlobalGenerator()->IndexTarget(&it->second);
this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
@@ -2193,7 +2219,7 @@ cmSourceGroup* cmMakefile::FindSourceGroup(
}
// Shouldn't get here, but just in case, return the default group.
- return &groups.front();
+ return groups.data();
}
#endif
@@ -2425,16 +2451,19 @@ bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
}
-std::string cmMakefile::GetRequiredDefinition(const std::string& name) const
+const std::string& cmMakefile::GetRequiredDefinition(
+ const std::string& name) const
{
- const char* ret = this->GetDefinition(name);
- if (!ret) {
+ static std::string const empty;
+ const std::string* def = GetDef(name);
+ if (!def) {
cmSystemTools::Error("Error required internal CMake variable not "
- "set, cmake may not be built correctly.\n",
- "Missing variable is:\n", name.c_str());
- return std::string();
+ "set, cmake may not be built correctly.\n"
+ "Missing variable is:\n" +
+ name);
+ return empty;
}
- return std::string(ret);
+ return *def;
}
bool cmMakefile::IsDefinitionSet(const std::string& name) const
@@ -2505,8 +2534,7 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
std::vector<std::string> cmMakefile::GetDefinitions() const
{
std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
- std::vector<std::string> cacheKeys = this->GetState()->GetCacheEntryKeys();
- res.insert(res.end(), cacheKeys.begin(), cacheKeys.end());
+ cmAppend(res, this->GetState()->GetCacheEntryKeys());
std::sort(res.begin(), res.end());
return res;
}
@@ -3055,10 +3083,8 @@ bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
// loop over all function blockers to see if any block this command
// evaluate in reverse, this is critical for balanced IF statements etc
- std::vector<cmFunctionBlocker*>::reverse_iterator pos;
- for (pos = this->FunctionBlockers.rbegin();
- pos != this->FunctionBlockers.rend(); ++pos) {
- if ((*pos)->IsFunctionBlocked(lff, *this, status)) {
+ for (cmFunctionBlocker* pos : cmReverseRange(this->FunctionBlockers)) {
+ if (pos->IsFunctionBlocked(lff, *this, status)) {
return true;
}
}
@@ -3546,7 +3572,7 @@ cmState* cmMakefile::GetState() const
return this->GetCMakeInstance()->GetState();
}
-void cmMakefile::DisplayStatus(const char* message, float s) const
+void cmMakefile::DisplayStatus(const std::string& message, float s) const
{
cmake* cm = this->GetCMakeInstance();
if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
@@ -3716,22 +3742,23 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
lineNumber, true, true);
}
-int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
- bool copyonly, bool atOnly, bool escapeQuotes,
+int cmMakefile::ConfigureFile(const std::string& infile,
+ const std::string& outfile, bool copyonly,
+ bool atOnly, bool escapeQuotes,
cmNewLineStyle newLine)
{
int res = 1;
if (!this->CanIWriteThisFile(outfile)) {
- cmSystemTools::Error("Attempt to write file: ", outfile,
+ cmSystemTools::Error("Attempt to write file: " + outfile +
" into a source directory.");
return 0;
}
if (!cmSystemTools::FileExists(infile)) {
- cmSystemTools::Error("File ", infile, " does not exist.");
+ cmSystemTools::Error("File " + infile + " does not exist.");
return 0;
}
std::string soutfile = outfile;
- std::string sinfile = infile;
+ const std::string& sinfile = infile;
this->AddCMakeDependFile(sinfile);
cmSystemTools::ConvertToUnixSlashes(soutfile);
@@ -3765,15 +3792,15 @@ int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
tempOutputFile += ".tmp";
cmsys::ofstream fout(tempOutputFile.c_str(), omode);
if (!fout) {
- cmSystemTools::Error("Could not open file for write in copy operation ",
- tempOutputFile.c_str());
+ cmSystemTools::Error("Could not open file for write in copy operation " +
+ tempOutputFile);
cmSystemTools::ReportLastSystemError("");
return 0;
}
cmsys::ifstream fin(sinfile.c_str());
if (!fin) {
- cmSystemTools::Error("Could not open file for read in copy operation ",
- sinfile.c_str());
+ cmSystemTools::Error("Could not open file for read in copy operation " +
+ sinfile);
return 0;
}
@@ -3860,7 +3887,7 @@ std::vector<std::string> cmMakefile::GetPropertyKeys() const
cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
{
- cmTargets::iterator i = this->Targets.find(name);
+ cmTargetMap::iterator i = this->Targets.find(name);
if (i != this->Targets.end()) {
return &i->second;
}
@@ -4273,7 +4300,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::CMP0065 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0066 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4711,6 +4738,13 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
needCxx17, needCxx20);
const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
+ if (existingCxxStandard == nullptr) {
+ const char* defaultCxxStandard =
+ this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+ if (defaultCxxStandard && *defaultCxxStandard) {
+ existingCxxStandard = defaultCxxStandard;
+ }
+ }
const char* const* existingCxxLevel = nullptr;
if (existingCxxStandard) {
existingCxxLevel =
@@ -4813,6 +4847,13 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target,
this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
const char* existingCStandard = target->GetProperty("C_STANDARD");
+ if (existingCStandard == nullptr) {
+ const char* defaultCStandard =
+ this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
+ if (defaultCStandard && *defaultCStandard) {
+ existingCStandard = defaultCStandard;
+ }
+ }
if (existingCStandard) {
if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) {
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 70a5689e1..d22334751 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -150,7 +150,7 @@ public:
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle = true,
bool uses_terminal = false, const std::string& depfile = "",
- bool command_expand_lists = false,
+ const std::string& job_pool = "", bool command_expand_lists = false,
ObjectLibraryCommands objLibraryCommands = RejectObjectLibraryCommands);
cmSourceFile* AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
@@ -160,14 +160,14 @@ public:
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
- const std::string& depfile = "");
+ const std::string& depfile = "", const std::string& job_pool = "");
cmSourceFile* 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 = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
- const std::string& depfile = "");
+ const std::string& depfile = "", const std::string& job_pool = "");
void AddCustomCommandOldStyle(const std::string& target,
const std::vector<std::string>& outputs,
const std::vector<std::string>& depends,
@@ -223,14 +223,14 @@ public:
const char* workingDirectory, 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);
+ bool command_expand_lists = false, const std::string& job_pool = "");
cmTarget* AddUtilityCommand(
const std::string& utilityName, TargetOrigin origin, bool excludeFromAll,
const char* workingDirectory, 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);
+ bool command_expand_lists = false, const std::string& job_pool = "");
/**
* Add a subdirectory to the build.
@@ -257,7 +257,7 @@ public:
* can be used in CMake to refer to lists, directories, etc.
*/
void AddDefinition(const std::string& name, const char* value);
- ///! Add a definition to this makefile and the global cmake cache.
+ //! Add a definition to this makefile and the global cmake cache.
void AddCacheDefinition(const std::string& name, const char* value,
const char* doc, cmStateEnums::CacheEntryType type,
bool force = false);
@@ -272,7 +272,7 @@ public:
* for cache entries, and will only affect the current makefile.
*/
void RemoveDefinition(const std::string& name);
- ///! Remove a definition from the cache.
+ //! Remove a definition from the cache.
void RemoveCacheDefinition(const std::string& name);
/**
@@ -313,6 +313,9 @@ public:
PolicyPushPop(cmMakefile* m);
~PolicyPushPop();
+ PolicyPushPop(const PolicyPushPop&) = delete;
+ PolicyPushPop& operator=(const PolicyPushPop&) = delete;
+
private:
cmMakefile* Makefile;
};
@@ -370,14 +373,13 @@ public:
return this->ComplainFileRegularExpression.c_str();
}
- /**
- * Get the list of targets
- */
- cmTargets& GetTargets() { return this->Targets; }
- /**
- * Get the list of targets, const version
- */
- const cmTargets& GetTargets() const { return this->Targets; }
+ // -- List of targets
+ typedef std::unordered_map<std::string, cmTarget> cmTargetMap;
+ /** Get the target map */
+ cmTargetMap& GetTargets() { return this->Targets; }
+ /** Get the target map - const version */
+ cmTargetMap const& GetTargets() const { return this->Targets; }
+
const std::vector<cmTarget*>& GetOwnedImportedTargets() const
{
return this->ImportedTargetsOwned;
@@ -436,7 +438,7 @@ public:
const char* GetDefinition(const std::string&) const;
const std::string* GetDef(const std::string&) const;
const std::string& GetSafeDefinition(const std::string&) const;
- std::string GetRequiredDefinition(const std::string& name) const;
+ const std::string& GetRequiredDefinition(const std::string& name) const;
bool IsDefinitionSet(const std::string&) const;
/**
* Get the list of all variables in the current space. If argument
@@ -545,7 +547,7 @@ public:
{
return this->ListFiles;
}
- ///! When the file changes cmake will be re-run from the build system.
+ //! When the file changes cmake will be re-run from the build system.
void AddCMakeDependFile(const std::string& file)
{
this->ListFiles.push_back(file);
@@ -607,8 +609,8 @@ public:
/**
* Copy file but change lines according to ConfigureString
*/
- int ConfigureFile(const char* infile, const char* outfile, bool copyonly,
- bool atOnly, bool escapeQuotes,
+ int ConfigureFile(const std::string& infile, const std::string& outfile,
+ bool copyonly, bool atOnly, bool escapeQuotes,
cmNewLineStyle = cmNewLineStyle());
/**
@@ -623,7 +625,7 @@ public:
bool ExecuteCommand(const cmListFileFunction& lff,
cmExecutionStatus& status);
- ///! Enable support for named language, if nil then all languages are
+ //! Enable support for named language, if nil then all languages are
/// enabled.
void EnableLanguage(std::vector<std::string> const& languages,
bool optional);
@@ -638,8 +640,8 @@ public:
cmVariableWatch* GetVariableWatch() const;
#endif
- ///! Display progress or status message.
- void DisplayStatus(const char*, float) const;
+ //! Display progress or status message.
+ void DisplayStatus(const std::string&, float) const;
/**
* Expand the given list file arguments into the full set after
@@ -674,7 +676,7 @@ public:
*/
cmSourceFile* GetSourceFileWithOutput(const std::string& outName) const;
- ///! Add a new cmTest to the list of tests for this makefile.
+ //! Add a new cmTest to the list of tests for this makefile.
cmTest* CreateTest(const std::string& testName);
/** Get a cmTest pointer for a given test name, if the name is
@@ -698,7 +700,7 @@ public:
std::string GetModulesFile(const std::string& name, bool& system) const;
- ///! Set/Get a property of this directory
+ //! Set/Get a property of this directory
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
@@ -707,7 +709,7 @@ public:
bool GetPropertyAsBool(const std::string& prop) const;
std::vector<std::string> GetPropertyKeys() const;
- ///! Initialize a makefile from its parent
+ //! Initialize a makefile from its parent
void InitializeFromParent(cmMakefile* parent);
void AddInstallGenerator(cmInstallGenerator* g)
@@ -743,6 +745,9 @@ public:
cmPolicies::PolicyMap const& pm);
~FunctionPushPop();
+ FunctionPushPop(const FunctionPushPop&) = delete;
+ FunctionPushPop& operator=(const FunctionPushPop&) = delete;
+
void Quiet() { this->ReportError = false; }
private:
@@ -757,6 +762,9 @@ public:
cmPolicies::PolicyMap const& pm);
~MacroPushPop();
+ MacroPushPop(const MacroPushPop&) = delete;
+ MacroPushPop& operator=(const MacroPushPop&) = delete;
+
void Quiet() { this->ReportError = false; }
private:
@@ -887,7 +895,7 @@ protected:
mutable std::set<cmListFileContext> CMP0054ReportedIds;
// libraries, classes, and executables
- mutable cmTargets Targets;
+ mutable cmTargetMap Targets;
std::map<std::string, std::string> AliasTargets;
typedef std::vector<cmSourceFile*> SourceFileVec;
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index e8ae5ae36..6b9b9c7f1 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -2,13 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileExecutableTargetGenerator.h"
-#include <algorithm>
#include <memory> // IWYU pragma: keep
+#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -31,19 +32,16 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
: cmMakefileTargetGenerator(target)
{
this->CustomCommandDriver = OnDepends;
- this->GeneratorTarget->GetExecutableNames(
- this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
- this->TargetNamePDB, this->ConfigName);
+ this->TargetNames =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName);
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
+ default;
void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
{
@@ -84,24 +82,9 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
bool relink)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
- if (!this->GlobalGenerator->GetLanguageEnabled("CUDA")) {
- return;
- }
-
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (!hasCUDA || !doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (!requiresDeviceLinking) {
return;
}
@@ -109,7 +92,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
// Get the language to use for linking this library.
std::string linkLanguage = "CUDA";
- std::string const objExt =
+ std::string const& objExt =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
// Build list of dependencies.
@@ -281,7 +264,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Write the build rule.
@@ -293,8 +276,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
this->WriteTargetDriverRule(targetOutputReal, relink);
// Clean all the possible executable names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(),
- exeCleanFiles.end());
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
#else
static_cast<void>(relink);
#endif
@@ -305,18 +287,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
std::vector<std::string> commands;
// Get the name of the executable to generate.
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetExecutableNames(targetName, targetNameReal,
- targetNameImport, targetNamePDB,
- this->ConfigName);
+ cmGeneratorTarget::Names targetNames =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName);
// Construct the full path version of the names.
std::string outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
if (this->GeneratorTarget->IsAppBundleOnApple()) {
- this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
+ this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath);
}
outpath += "/";
std::string outpathImp;
@@ -326,12 +303,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
outpathImp = outpath;
}
} else {
cmSystemTools::MakeDirectory(outpath);
- if (!targetNameImport.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
outpathImp = this->GeneratorTarget->GetDirectory(
this->ConfigName, cmStateEnums::ImportLibraryArtifact);
cmSystemTools::MakeDirectory(outpathImp);
@@ -348,10 +325,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
cmSystemTools::MakeDirectory(pdbOutputPath);
pdbOutputPath += "/";
- std::string targetFullPath = outpath + targetName;
- std::string targetFullPathReal = outpath + targetNameReal;
- std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
- std::string targetFullPathImport = outpathImp + targetNameImport;
+ std::string targetFullPath = outpath + targetNames.Output;
+ std::string targetFullPathReal = outpath + targetNames.Real;
+ std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
+ std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
targetFullPathPDB, cmOutputConverter::SHELL);
// Convert to the output path to use in constructing commands.
@@ -376,8 +353,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
// Make sure we have a link language.
if (linkLanguage.empty()) {
- cmSystemTools::Error("Cannot determine link language for target \"",
- this->GeneratorTarget->GetName().c_str(), "\".");
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
return;
}
@@ -468,11 +445,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPath + ".manifest"));
#endif
- if (targetNameReal != targetName) {
+ if (this->TargetNames.Real != this->TargetNames.Output) {
exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
}
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPathImport));
@@ -487,7 +464,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
// List the PDB for cleaning only when the whole target is
// cleaned. We do not want to delete the .pdb file just before
// linking the target.
- this->CleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
// Add the pre-build and pre-link rules building but not when relinking.
@@ -657,7 +634,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Add a rule to create necessary symlinks for the library.
@@ -670,7 +647,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
@@ -702,6 +679,5 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->WriteTargetDriverRule(targetFullPath, relink);
// Clean all the possible executable names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(),
- exeCleanFiles.end());
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
}
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 5a1ef4efe..b9f7c6d13 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -2,13 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileLibraryTargetGenerator.h"
-#include <algorithm>
#include <memory> // IWYU pragma: keep
+#include <set>
#include <sstream>
#include <stddef.h>
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -32,20 +33,17 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
{
this->CustomCommandDriver = OnDepends;
if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
- this->GeneratorTarget->GetLibraryNames(
- this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
- this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
+ this->TargetNames =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName);
}
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator() =
+ default;
void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
{
@@ -125,20 +123,9 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, false);
}
@@ -164,19 +151,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
}
if (!relink) {
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink);
}
@@ -208,21 +185,10 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
{
-
if (!relink) {
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink);
}
@@ -306,8 +272,8 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
}
// Clean files associated with this library.
- std::vector<std::string> libCleanFiles;
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal));
// Determine whether a link script will be used.
@@ -414,8 +380,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
this->LocalGenerator->SetLinkScriptShell(false);
// Clean all the possible library names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(),
- libCleanFiles.end());
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
}
std::vector<std::string> commands1;
@@ -432,7 +397,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Compute the list of outputs.
@@ -463,8 +428,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Make sure we have a link language.
if (linkLanguage.empty()) {
- cmSystemTools::Error("Cannot determine link language for target \"",
- this->GeneratorTarget->GetName().c_str(), "\".");
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
return;
}
@@ -489,25 +454,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
// Construct the name of the library.
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
- targetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName);
// Construct the full path version of the names.
std::string outpath;
std::string outpathImp;
if (this->GeneratorTarget->IsFrameworkOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
- this->OSXBundleGenerator->CreateFramework(targetName, outpath);
+ this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+ outpath);
outpath += "/";
} else if (this->GeneratorTarget->IsCFBundleOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
- this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
+ outpath);
outpath += "/";
} else if (relink) {
outpath = this->Makefile->GetCurrentBinaryDirectory();
@@ -515,14 +475,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
outpathImp = outpath;
}
} else {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
outpathImp = this->GeneratorTarget->GetDirectory(
this->ConfigName, cmStateEnums::ImportLibraryArtifact);
cmSystemTools::MakeDirectory(outpathImp);
@@ -539,11 +499,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
cmSystemTools::MakeDirectory(pdbOutputPath);
pdbOutputPath += "/";
- std::string targetFullPath = outpath + targetName;
- std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
- std::string targetFullPathSO = outpath + targetNameSO;
- std::string targetFullPathReal = outpath + targetNameReal;
- std::string targetFullPathImport = outpathImp + targetNameImport;
+ std::string targetFullPath = outpath + this->TargetNames.Output;
+ std::string targetFullPathPDB = pdbOutputPath + this->TargetNames.PDB;
+ std::string targetFullPathSO = outpath + this->TargetNames.SharedObject;
+ std::string targetFullPathReal = outpath + this->TargetNames.Real;
+ std::string targetFullPathImport =
+ outpathImp + this->TargetNames.ImportLibrary;
// Construct the output path version of the names for use in command
// arguments.
@@ -599,8 +560,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
// Clean files associated with this library.
- std::vector<std::string> libCleanFiles;
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
std::vector<std::string> commands1;
@@ -612,26 +573,27 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
- if (targetName != targetNameReal) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (this->TargetNames.Output != this->TargetNames.Real) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
}
- if (targetNameSO != targetNameReal && targetNameSO != targetName) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (this->TargetNames.SharedObject != this->TargetNames.Real &&
+ this->TargetNames.SharedObject != this->TargetNames.Output) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO));
}
- if (!targetNameImport.empty()) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPathImport));
std::string implib;
if (this->GeneratorTarget->GetImplibGNUtoMS(
this->ConfigName, targetFullPathImport, implib)) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
}
}
@@ -639,14 +601,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// List the PDB for cleaning only when the whole target is
// cleaned. We do not want to delete the .pdb file just before
// linking the target.
- this->CleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
#ifdef _WIN32
// There may be a manifest file for this target. Add it to the
// clean set just in case.
if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPath + ".manifest"));
}
@@ -820,7 +782,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.ObjectsQuoted = buildObjs.c_str();
if (this->GeneratorTarget->HasSOName(this->ConfigName)) {
vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
- vars.TargetSOName = targetNameSO.c_str();
+ vars.TargetSOName = this->TargetNames.SharedObject.c_str();
}
vars.LinkFlags = linkFlags.c_str();
@@ -951,7 +913,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Add a rule to create necessary symlinks for the library.
@@ -968,7 +930,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
@@ -981,10 +943,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Compute the list of outputs.
std::vector<std::string> outputs(1, targetFullPathReal);
- if (targetNameSO != targetNameReal) {
+ if (this->TargetNames.SharedObject != this->TargetNames.Real) {
outputs.push_back(targetFullPathSO);
}
- if (targetName != targetNameSO && targetName != targetNameReal) {
+ if (this->TargetNames.Output != this->TargetNames.SharedObject &&
+ this->TargetNames.Output != this->TargetNames.Real) {
outputs.push_back(targetFullPath);
}
@@ -996,6 +959,5 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->WriteTargetDriverRule(targetFullPath, relink);
// Clean all the possible library names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(),
- libCleanFiles.end());
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
}
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index af34169c3..b3bab4b08 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -21,6 +21,7 @@
#include "cmMakefileLibraryTargetGenerator.h"
#include "cmMakefileUtilityTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -146,21 +147,41 @@ void cmMakefileTargetGenerator::CreateRuleFile()
void cmMakefileTargetGenerator::WriteTargetBuildRules()
{
+ // -- Write the custom commands for this target
+
const std::string& config =
this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
- // write the custom commands for this target
- // Look for files registered for cleaning in this directory.
- if (const char* additional_clean_files =
- this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
+ // Evaluates generator expressions and expands prop_value
+ auto evaluatedFiles =
+ [this, &config](const char* prop_value) -> std::vector<std::string> {
+ std::vector<std::string> files;
cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(additional_clean_files);
-
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop_value);
cmSystemTools::ExpandListArgument(
cge->Evaluate(this->LocalGenerator, config, false, this->GeneratorTarget,
nullptr, nullptr),
- this->CleanFiles);
+ files);
+ return files;
+ };
+
+ // Look for additional files registered for cleaning in this directory.
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(prop_value);
+ this->CleanFiles.insert(files.begin(), files.end());
+ }
+
+ // Look for additional files registered for cleaning in this target.
+ if (const char* prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(prop_value);
+ // For relative path support
+ std::string const& binaryDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (std::string const& cfl : files) {
+ this->CleanFiles.insert(cmSystemTools::CollapseFullPath(cfl, binaryDir));
+ }
}
// add custom commands to the clean rules?
@@ -180,13 +201,13 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
if (clean) {
const std::vector<std::string>& outputs = ccg.GetOutputs();
for (std::string const& output : outputs) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
output));
}
const std::vector<std::string>& byproducts = ccg.GetByproducts();
for (std::string const& byproduct : byproducts) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
byproduct));
}
@@ -198,19 +219,14 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
std::vector<cmCustomCommand> buildEventCommands =
this->GeneratorTarget->GetPreBuildCommands();
- buildEventCommands.insert(
- buildEventCommands.end(),
- this->GeneratorTarget->GetPreLinkCommands().begin(),
- this->GeneratorTarget->GetPreLinkCommands().end());
- buildEventCommands.insert(
- buildEventCommands.end(),
- this->GeneratorTarget->GetPostBuildCommands().begin(),
- this->GeneratorTarget->GetPostBuildCommands().end());
+ cmAppend(buildEventCommands, this->GeneratorTarget->GetPreLinkCommands());
+ cmAppend(buildEventCommands,
+ this->GeneratorTarget->GetPostBuildCommands());
for (const auto& be : buildEventCommands) {
const std::vector<std::string>& byproducts = be.GetByproducts();
for (std::string const& byproduct : byproducts) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
byproduct));
}
@@ -349,7 +365,7 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()(
std::string output = macdir;
output += "/";
output += cmSystemTools::GetFilenameName(input);
- this->Generator->CleanFiles.push_back(
+ this->Generator->CleanFiles.insert(
this->Generator->LocalGenerator->MaybeConvertToRelativePath(
this->Generator->LocalGenerator->GetCurrentBinaryDirectory(), output));
output = this->Generator->LocalGenerator->MaybeConvertToRelativePath(
@@ -414,7 +430,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Save this in the target's list of object files.
this->Objects.push_back(obj);
- this->CleanFiles.push_back(obj);
+ this->CleanFiles.insert(obj);
// TODO: Remove
// std::string relativeObj
@@ -654,19 +670,20 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileRule, compileCommands);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
- std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+ const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileRule, compileCommands);
}
@@ -766,8 +783,12 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
if (!compileCommands.empty() && !compilerLauncher.empty()) {
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(compilerLauncher, args, true);
- for (std::string& i : args) {
- i = this->LocalGenerator->EscapeForShell(i);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
}
compileCommands.front().insert(0, cmJoin(args, " ") + " ");
}
@@ -793,8 +814,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
this->LocalGenerator->CreateCDCommand(
compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), compileCommands.begin(),
- compileCommands.end());
+ cmAppend(commands, compileCommands);
}
// Check for extra outputs created by the compilation.
@@ -802,8 +822,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
if (const char* extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
// Register these as extra files to clean.
cmSystemTools::ExpandListArgument(extra_outputs_str, outputs);
- this->CleanFiles.insert(this->CleanFiles.end(), outputs.begin() + 1,
- outputs.end());
+ this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
}
// Write the rule.
@@ -857,8 +876,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
preprocessCommands,
this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), preprocessCommands.begin(),
- preprocessCommands.end());
+ cmAppend(commands, preprocessCommands);
} else {
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
cmd += preprocessRuleVar;
@@ -904,8 +922,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
this->LocalGenerator->CreateCDCommand(
assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), assemblyCommands.begin(),
- assemblyCommands.end());
+ cmAppend(commands, assemblyCommands);
} else {
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
cmd += assemblyRuleVar;
@@ -974,18 +991,17 @@ bool cmMakefileTargetGenerator::WriteMakeRule(
// For multiple outputs, make the extra ones depend on the first one.
std::vector<std::string> const output_depends(1, outputs[0]);
std::string binDir = this->LocalGenerator->GetBinaryDirectory();
- for (std::vector<std::string>::const_iterator o = outputs.begin() + 1;
- o != outputs.end(); ++o) {
+ for (std::string const& output : cmMakeRange(outputs).advance(1)) {
// Touch the extra output so "make" knows that it was updated,
// but only if the output was actually created.
std::string const out = this->LocalGenerator->ConvertToOutputFormat(
- this->LocalGenerator->MaybeConvertToRelativePath(binDir, *o),
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, output),
cmOutputConverter::SHELL);
std::vector<std::string> output_commands;
bool o_symbolic = false;
if (need_symbolic) {
- if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
@@ -994,13 +1010,13 @@ bool cmMakefileTargetGenerator::WriteMakeRule(
if (!o_symbolic) {
output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
}
- this->LocalGenerator->WriteMakeRule(os, nullptr, *o, output_depends,
+ this->LocalGenerator->WriteMakeRule(os, nullptr, output, output_depends,
output_commands, o_symbolic, in_help);
if (!o_symbolic) {
// At build time, remove the first output if this one does not exist
// so that "make" will rerun the real commands that create this one.
- MultipleOutputPairsType::value_type p(*o, outputs[0]);
+ MultipleOutputPairsType::value_type p(output, outputs[0]);
this->MultipleOutputPairs.insert(p);
}
}
@@ -1153,8 +1169,7 @@ void cmMakefileTargetGenerator::DriveCustomCommands(
if (cmCustomCommand* cc = source->GetCustomCommand()) {
cmCustomCommandGenerator ccg(*cc, this->ConfigName,
this->LocalGenerator);
- const std::vector<std::string>& outputs = ccg.GetOutputs();
- depends.insert(depends.end(), outputs.begin(), outputs.end());
+ cmAppend(depends, ccg.GetOutputs());
}
}
}
@@ -1378,8 +1393,7 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule(
}
// Make sure the extra files are built.
- depends.insert(depends.end(), this->ExtraFiles.begin(),
- this->ExtraFiles.end());
+ cmAppend(depends, this->ExtraFiles);
}
// Write the driver rule.
@@ -1398,11 +1412,10 @@ void cmMakefileTargetGenerator::AppendTargetDepends(
}
// Loop over all library dependencies.
- const char* cfg = this->LocalGenerator->GetConfigName().c_str();
+ const std::string& cfg = this->LocalGenerator->GetConfigName();
if (cmComputeLinkInformation* cli =
this->GeneratorTarget->GetLinkInformation(cfg)) {
- std::vector<std::string> const& libDeps = cli->GetDepends();
- depends.insert(depends.end(), libDeps.begin(), libDeps.end());
+ cmAppend(depends, cli->GetDepends());
}
}
@@ -1419,8 +1432,7 @@ void cmMakefileTargetGenerator::AppendObjectDepends(
}
// Add dependencies on the external object files.
- depends.insert(depends.end(), this->ExternalObjects.begin(),
- this->ExternalObjects.end());
+ cmAppend(depends, this->ExternalObjects);
// Add a dependency on the rule file itself.
this->LocalGenerator->AppendRuleDepend(depends,
@@ -1603,7 +1615,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs(
{
std::string frameworkPath;
std::string linkPath;
- std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
cmComputeLinkInformation* pcli =
this->GeneratorTarget->GetLinkInformation(config);
this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index 529b4db44..c570a7ccf 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -12,12 +12,12 @@
#include <vector>
#include "cmCommonTargetGenerator.h"
+#include "cmGeneratorTarget.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmOSXBundleGenerator.h"
class cmCustomCommandGenerator;
class cmGeneratedFileStream;
-class cmGeneratorTarget;
class cmGlobalUnixMakefileGenerator3;
class cmLinkLineComputer;
class cmOutputConverter;
@@ -210,7 +210,7 @@ protected:
cmGeneratedFileStream* InfoFileStream;
// files to clean
- std::vector<std::string> CleanFiles;
+ std::set<std::string> CleanFiles;
// objects used by this target
std::vector<std::string> Objects;
@@ -231,15 +231,11 @@ protected:
bool in_help = false);
// Target name info.
- std::string TargetNameOut;
- std::string TargetNameSO;
- std::string TargetNameReal;
- std::string TargetNameImport;
- std::string TargetNamePDB;
+ cmGeneratorTarget::Names TargetNames;
// macOS content info.
std::set<std::string> MacContentFolders;
- cmOSXBundleGenerator* OSXBundleGenerator;
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
MacOSXContentGeneratorType* MacOSXContentGenerator;
};
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
index 8fbd5d2bd..42369954c 100644
--- a/Source/cmMakefileUtilityTargetGenerator.cxx
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -21,14 +22,12 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
{
this->CustomCommandDriver = OnUtility;
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator() =
+ default;
void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
{
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 95f5fcbbe..5320ec570 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -6,7 +6,11 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmMessenger.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cassert>
class cmExecutionStatus;
@@ -18,49 +22,88 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- std::vector<std::string>::const_iterator i = args.begin();
+ auto i = args.cbegin();
- MessageType type = MessageType::MESSAGE;
- bool status = false;
- bool fatal = false;
+ auto type = MessageType::MESSAGE;
+ auto status = false;
+ auto fatal = false;
+ auto level = cmake::LogLevel::LOG_UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "FATAL_ERROR") {
fatal = true;
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "WARNING") {
type = MessageType::WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
++i;
} else if (*i == "AUTHOR_WARNING") {
if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true;
type = MessageType::AUTHOR_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "STATUS") {
status = true;
+ level = cmake::LogLevel::LOG_STATUS;
+ ++i;
+ } else if (*i == "VERBOSE") {
+ status = true;
+ level = cmake::LogLevel::LOG_VERBOSE;
+ ++i;
+ } else if (*i == "DEBUG") {
+ status = true;
+ level = cmake::LogLevel::LOG_DEBUG;
+ ++i;
+ } else if (*i == "TRACE") {
+ status = true;
+ level = cmake::LogLevel::LOG_TRACE;
++i;
} else if (*i == "DEPRECATION") {
if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true;
type = MessageType::DEPRECATION_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
type = MessageType::DEPRECATION_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
+ } else if (*i == "NOTICE") {
+ // `NOTICE` message type is going to be output to stderr
+ level = cmake::LogLevel::LOG_NOTICE;
+ ++i;
+ } else {
+ // Messages w/o any type are `NOTICE`s
+ level = cmake::LogLevel::LOG_NOTICE;
+ }
+ assert("Message log level expected to be set" &&
+ level != cmake::LogLevel::LOG_UNDEFINED);
+
+ auto desiredLevel = this->Makefile->GetCMakeInstance()->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
+
+ if (desiredLevel < level) {
+ // Suppress the message
+ return true;
}
- std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+ auto message = cmJoin(cmMakeRange(i, args.cend()), "");
if (type != MessageType::MESSAGE) {
// we've overridden the message type, above, so display it directly
@@ -68,7 +111,7 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
m->DisplayMessage(type, message, this->Makefile->GetBacktrace());
} else {
if (status) {
- this->Makefile->DisplayStatus(message.c_str(), -1);
+ this->Makefile->DisplayStatus(message, -1);
} else {
cmSystemTools::Message(message);
}
diff --git a/Source/cmNinjaLinkLineDeviceComputer.cxx b/Source/cmNinjaLinkLineDeviceComputer.cxx
new file mode 100644
index 000000000..84c1b37d3
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.cxx
@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmNinjaLinkLineDeviceComputer.h"
+
+#include "cmGlobalNinjaGenerator.h"
+
+cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg)
+ : cmLinkLineDeviceComputer(outputConverter, stateDir)
+ , GG(gg)
+{
+}
+
+std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+ return GG->ConvertToNinjaPath(lib);
+}
diff --git a/Source/cmNinjaLinkLineDeviceComputer.h b/Source/cmNinjaLinkLineDeviceComputer.h
new file mode 100644
index 000000000..84ced5b35
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmNinjaLinkLineDeviceComputer_h
+#define cmNinjaLinkLineDeviceComputer_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include "cmLinkLineDeviceComputer.h"
+
+class cmGlobalNinjaGenerator;
+class cmOutputConverter;
+class cmStateDirectory;
+
+class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer
+{
+public:
+ cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg);
+
+ cmNinjaLinkLineDeviceComputer(cmNinjaLinkLineDeviceComputer const&) = delete;
+ cmNinjaLinkLineDeviceComputer& operator=(
+ cmNinjaLinkLineDeviceComputer const&) = delete;
+
+ std::string ConvertToLinkReference(std::string const& input) const override;
+
+private:
+ cmGlobalNinjaGenerator const* GG;
+};
+
+#endif
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index becc42433..f65abc839 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -12,6 +12,7 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
@@ -21,6 +22,7 @@
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
+#include "cmNinjaLinkLineDeviceComputer.h"
#include "cmNinjaTypes.h"
#include "cmOSXBundleGenerator.h"
#include "cmOutputConverter.h"
@@ -32,8 +34,6 @@
#include "cmStateTypes.h"
#include "cmSystemTools.h"
-class cmCustomCommand;
-
cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
cmGeneratorTarget* target)
: cmNinjaTargetGenerator(target)
@@ -41,13 +41,10 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
{
this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
if (target->GetType() == cmStateEnums::EXECUTABLE) {
- this->GetGeneratorTarget()->GetExecutableNames(
- this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
- this->TargetNamePDB, GetLocalGenerator()->GetConfigName());
+ this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames(
+ GetLocalGenerator()->GetConfigName());
} else {
- this->GetGeneratorTarget()->GetLibraryNames(
- this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
- this->TargetNameImport, this->TargetNamePDB,
+ this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames(
GetLocalGenerator()->GetConfigName());
}
@@ -58,21 +55,18 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
}
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->GetConfigName());
+ cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName());
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
void cmNinjaNormalTargetGenerator::Generate()
{
if (this->TargetLinkLanguage.empty()) {
cmSystemTools::Error("CMake can not determine linker language for "
- "target: ",
- this->GetGeneratorTarget()->GetName().c_str());
+ "target: " +
+ this->GetGeneratorTarget()->GetName());
return;
}
@@ -90,6 +84,8 @@ void cmNinjaNormalTargetGenerator::Generate()
this->WriteDeviceLinkStatement();
this->WriteLinkStatement();
}
+
+ this->AdditionalCleanFiles();
}
void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
@@ -166,13 +162,8 @@ struct cmNinjaRemoveNoOpCommands
void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
{
- cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
- std::string ruleName = this->LanguageLinkerDeviceRule();
- // Select whether to use a response file for objects.
- std::string rspfile;
- std::string rspcontent;
-
- if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+ cmNinjaRule rule(this->LanguageLinkerDeviceRule());
+ if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType =
@@ -180,32 +171,24 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
vars.Language = "CUDA";
- std::string responseFlag;
- if (!useResponseFile) {
+ // build response file name
+ std::string responseFlag = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_CUDA_RESPONSE_FILE_LINK_FLAG");
+
+ if (!useResponseFile || responseFlag.empty()) {
vars.Objects = "$in";
vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
} else {
- std::string cmakeVarLang = "CMAKE_";
- cmakeVarLang += this->TargetLinkLanguage;
-
- // build response file name
- std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
- const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
- if (flag) {
- responseFlag = flag;
- } else {
- responseFlag = "@";
- }
- rspfile = "$RSP_FILE";
- responseFlag += rspfile;
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
// build response file content
if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
- rspcontent = "$in";
+ rule.RspContent = "$in";
} else {
- rspcontent = "$in_newline";
+ rule.RspContent = "$in_newline";
}
- rspcontent += " $LINK_LIBRARIES";
+ rule.RspContent += " $LINK_LIBRARIES";
vars.Objects = responseFlag.c_str();
vars.LinkLibraries = "";
}
@@ -224,7 +207,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
vars.Manifests = "$MANIFESTS";
std::string langFlags;
- if (targetType != cmStateEnums::EXECUTABLE) {
+ if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) {
langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
vars.LanguageCompileFlags = langFlags.c_str();
}
@@ -251,69 +234,84 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
// If there is no ranlib the command will be ":". Skip it.
cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
- std::string linkCmd =
- this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
// Write the linker rule with response file if needed.
- std::ostringstream comment;
- comment << "Rule for linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << ".";
- std::ostringstream description;
- description << "Linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << " $TARGET_FILE";
- this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
- comment.str(),
- /*depfile*/ "",
- /*deptype*/ "", rspfile, rspcontent,
- /*restat*/ "$RESTAT",
- /*generator*/ false);
+ rule.Comment = "Rule for linking ";
+ rule.Comment += this->TargetLinkLanguage;
+ rule.Comment += " ";
+ rule.Comment += this->GetVisibleTypeName();
+ rule.Comment += ".";
+ rule.Description = "Linking ";
+ rule.Description += this->TargetLinkLanguage;
+ rule.Description += " ";
+ rule.Description += this->GetVisibleTypeName();
+ rule.Description += " $TARGET_FILE";
+ rule.Restat = "$RESTAT";
+
+ this->GetGlobalGenerator()->AddRule(rule);
}
}
void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
{
cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
- std::string ruleName = this->LanguageLinkerRule();
- // Select whether to use a response file for objects.
- std::string rspfile;
- std::string rspcontent;
-
- if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+ std::string linkRuleName = this->LanguageLinkerRule();
+ if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
+ cmNinjaRule rule(std::move(linkRuleName));
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
- vars.CMTargetType =
- cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
+ vars.CMTargetType = cmState::GetTargetTypeName(targetType);
vars.Language = this->TargetLinkLanguage.c_str();
+ if (this->TargetLinkLanguage == "Swift") {
+ vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
+ vars.SwiftModule = "$SWIFT_MODULE";
+ vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
+ vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP";
+ vars.SwiftSources = "$SWIFT_SOURCES";
+
+ vars.Defines = "$DEFINES";
+ vars.Flags = "$FLAGS";
+ vars.Includes = "$INCLUDES";
+ }
+
std::string responseFlag;
- if (!useResponseFile) {
+
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += this->TargetLinkLanguage;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+
+ if (flag) {
+ responseFlag = flag;
+ } else if (this->TargetLinkLanguage != "CUDA") {
+ responseFlag = "@";
+ }
+
+ if (!useResponseFile || responseFlag.empty()) {
vars.Objects = "$in";
vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
} else {
- std::string cmakeVarLang = "CMAKE_";
- cmakeVarLang += this->TargetLinkLanguage;
-
- // build response file name
- std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
- const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
- if (flag) {
- responseFlag = flag;
- } else {
- responseFlag = "@";
- }
- rspfile = "$RSP_FILE";
- responseFlag += rspfile;
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
// build response file content
if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
- rspcontent = "$in";
+ rule.RspContent = "$in";
} else {
- rspcontent = "$in_newline";
+ rule.RspContent = "$in_newline";
+ }
+ rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
+ if (this->TargetLinkLanguage == "Swift") {
+ vars.SwiftSources = responseFlag.c_str();
+ } else {
+ vars.Objects = responseFlag.c_str();
}
- rspcontent += " $LINK_PATH $LINK_LIBRARIES";
- vars.Objects = responseFlag.c_str();
vars.LinkLibraries = "";
}
@@ -377,65 +375,51 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
linkCmds.emplace_back("$POST_BUILD");
- std::string linkCmd =
- this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
// Write the linker rule with response file if needed.
- std::ostringstream comment;
- comment << "Rule for linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << ".";
- std::ostringstream description;
- description << "Linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << " $TARGET_FILE";
- this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
- comment.str(),
- /*depfile*/ "",
- /*deptype*/ "", rspfile, rspcontent,
- /*restat*/ "$RESTAT",
- /*generator*/ false);
+ rule.Comment = "Rule for linking ";
+ rule.Comment += this->TargetLinkLanguage;
+ rule.Comment += " ";
+ rule.Comment += this->GetVisibleTypeName();
+ rule.Comment += ".";
+ rule.Description = "Linking ";
+ rule.Description += this->TargetLinkLanguage;
+ rule.Description += " ";
+ rule.Description += this->GetVisibleTypeName();
+ rule.Description += " $TARGET_FILE";
+ rule.Restat = "$RESTAT";
+ this->GetGlobalGenerator()->AddRule(rule);
}
- if (this->TargetNameOut != this->TargetNameReal &&
+ if (this->TargetNames.Output != this->TargetNames.Real &&
!this->GetGeneratorTarget()->IsFrameworkOnApple()) {
std::string cmakeCommand =
this->GetLocalGenerator()->ConvertToOutputFormat(
cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
if (targetType == cmStateEnums::EXECUTABLE) {
- std::vector<std::string> commandLines;
- commandLines.push_back(cmakeCommand +
- " -E cmake_symlink_executable $in $out");
- commandLines.emplace_back("$POST_BUILD");
-
- this->GetGlobalGenerator()->AddRule(
- "CMAKE_SYMLINK_EXECUTABLE",
- this->GetLocalGenerator()->BuildCommandLine(commandLines),
- "Creating executable symlink $out",
- "Rule for creating "
- "executable symlink.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("CMAKE_SYMLINK_EXECUTABLE");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand + " -E cmake_symlink_executable $in $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating executable symlink $out";
+ rule.Comment = "Rule for creating executable symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
} else {
- std::vector<std::string> commandLines;
- commandLines.push_back(cmakeCommand +
- " -E cmake_symlink_library $in $SONAME $out");
- commandLines.emplace_back("$POST_BUILD");
-
- this->GetGlobalGenerator()->AddRule(
- "CMAKE_SYMLINK_LIBRARY",
- this->GetLocalGenerator()->BuildCommandLine(commandLines),
- "Creating library symlink $out",
- "Rule for creating "
- "library symlink.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("CMAKE_SYMLINK_LIBRARY");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand +
+ " -E cmake_symlink_library $in $SONAME $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating library symlink $out";
+ rule.Comment = "Rule for creating library symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
}
}
}
@@ -565,38 +549,16 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
{
- if (!this->GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ if (!globalGen->GetLanguageEnabled("CUDA")) {
return;
}
- cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
-
- // determine if we need to do any device linking for this target
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- genTarget.GetLinkClosure(this->GetConfigName());
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- genTarget.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- } else {
- switch (genTarget.GetType()) {
- case cmStateEnums::SHARED_LIBRARY:
- case cmStateEnums::MODULE_LIBRARY:
- case cmStateEnums::EXECUTABLE:
- doDeviceLinking = true;
- break;
- default:
- break;
- }
- }
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
- if (!(doDeviceLinking && hasCUDA)) {
+ bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName);
+ if (!requiresDeviceLinking) {
return;
}
@@ -605,44 +567,44 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
// First and very important step is to make sure while inside this
// step our link language is set to CUDA
std::string cudaLinkLanguage = "CUDA";
- std::string const objExt =
+ std::string const& objExt =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
std::string const cfgName = this->GetConfigName();
std::string const targetOutputReal = ConvertToNinjaPath(
- genTarget.ObjectDirectory + "cmake_device_link" + objExt);
+ genTarget->ObjectDirectory + "cmake_device_link" + objExt);
std::string const targetOutputImplib = ConvertToNinjaPath(
- genTarget.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+ genTarget->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
this->DeviceLinkObject = targetOutputReal;
// Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
- const cmStateEnums::TargetType targetType = genTarget.GetType();
+ const cmStateEnums::TargetType targetType = genTarget->GetType();
this->GetBuildFileStream() << "# Device Link build statements for "
<< cmState::GetTargetTypeName(targetType)
<< " target " << this->GetTargetName() << "\n\n";
// Compute the comment.
- std::ostringstream comment;
- comment << "Link the " << this->GetVisibleTypeName() << " "
- << targetOutputReal;
+ cmNinjaBuild build(this->LanguageLinkerDeviceRule());
+ build.Comment = "Link the ";
+ build.Comment += this->GetVisibleTypeName();
+ build.Comment += " ";
+ build.Comment += targetOutputReal;
- cmNinjaDeps emptyDeps;
- cmNinjaVars vars;
+ cmNinjaVars& vars = build.Variables;
// Compute outputs.
- cmNinjaDeps outputs;
- outputs.push_back(targetOutputReal);
+ build.Outputs.push_back(targetOutputReal);
// Compute specific libraries to link with.
- cmNinjaDeps explicitDeps = this->GetObjects();
- cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+ build.ExplicitDeps = this->GetObjects();
+ build.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
std::string frameworkPath;
std::string linkPath;
- std::string createRule = genTarget.GetCreateRuleVariable(
+ std::string createRule = genTarget->GetCreateRuleVariable(
this->TargetLinkLanguage, this->GetConfigName());
const bool useWatcomQuote =
this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE");
@@ -655,14 +617,14 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
new cmNinjaLinkLineDeviceComputer(
this->GetLocalGenerator(),
this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(),
- this->GetGlobalGenerator()));
+ globalGen));
linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
localGen.GetTargetFlags(
linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
- vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
+ vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
- this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars);
+ this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
vars["LINK_FLAGS"] =
cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
@@ -676,21 +638,21 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
// code between the Makefile executable and library generators.
if (targetType == cmStateEnums::EXECUTABLE) {
std::string t = vars["FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = t;
t.clear();
- localGen.AddLanguageFlagsForLinking(t, &genTarget, cudaLinkLanguage,
+ localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage,
cfgName);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
- if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
+ if (genTarget->HasSOName(cfgName)) {
vars["SONAME_FLAG"] =
this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
- vars["SONAME"] = this->TargetNameSO;
+ vars["SONAME"] = this->TargetNames.SharedObject;
if (targetType == cmStateEnums::SHARED_LIBRARY) {
std::string install_dir =
this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
@@ -701,7 +663,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
}
}
- if (!this->TargetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
const std::string impLibPath = localGen.ConvertToOutputFormat(
targetOutputImplib, cmOutputConverter::SHELL);
vars["TARGET_IMPLIB"] = impLibPath;
@@ -715,7 +677,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
this->SetMsvcTargetPdbVariable(vars);
- if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ if (globalGen->IsGCCOnWindows()) {
// ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
std::string& linkLibraries = vars["LINK_LIBRARIES"];
std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
@@ -723,102 +685,173 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
std::replace(link_path.begin(), link_path.end(), '\\', '/');
}
- cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
-
// Device linking currently doesn't support response files so
// do not check if the user has explicitly forced a response file.
int const commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
- globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule());
+ globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule());
- const std::string rspfile = this->ConvertToNinjaPath(
- std::string("CMakeFiles/") + genTarget.GetName() + ".rsp");
+ build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
+ genTarget->GetName() + ".rsp");
// Gather order-only dependencies.
- cmNinjaDeps orderOnlyDeps;
this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- orderOnlyDeps);
+ build.OrderOnlyDeps);
// Write the build statement for this target.
bool usedResponseFile = false;
- globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
- this->LanguageLinkerDeviceRule(), outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
- implicitDeps, orderOnlyDeps, vars, rspfile,
- commandLineLengthLimit, &usedResponseFile);
- this->WriteDeviceLinkRule(false);
+ globalGen->WriteBuild(this->GetBuildFileStream(), build,
+ commandLineLengthLimit, &usedResponseFile);
+ this->WriteDeviceLinkRule(usedResponseFile);
}
void cmNinjaNormalTargetGenerator::WriteLinkStatement()
{
- cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ cmMakefile* mf = this->GetMakefile();
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ cmGeneratorTarget* gt = this->GetGeneratorTarget();
+
const std::string cfgName = this->GetConfigName();
- std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
+ std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(cfgName));
std::string targetOutputReal = ConvertToNinjaPath(
- gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
- /*realname=*/true));
+ gt->GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true));
std::string targetOutputImplib = ConvertToNinjaPath(
- gt.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+ gt->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
- if (gt.IsAppBundleOnApple()) {
+ if (gt->IsAppBundleOnApple()) {
// Create the app bundle
- std::string outpath = gt.GetDirectory(cfgName);
- this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+ std::string outpath = gt->GetDirectory(cfgName);
+ this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output,
+ outpath);
// Calculate the output path
targetOutput = outpath;
targetOutput += "/";
- targetOutput += this->TargetNameOut;
+ targetOutput += this->TargetNames.Output;
targetOutput = this->ConvertToNinjaPath(targetOutput);
targetOutputReal = outpath;
targetOutputReal += "/";
- targetOutputReal += this->TargetNameReal;
+ targetOutputReal += this->TargetNames.Real;
targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
- } else if (gt.IsFrameworkOnApple()) {
+ } else if (gt->IsFrameworkOnApple()) {
// Create the library framework.
- this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
- gt.GetDirectory(cfgName));
- } else if (gt.IsCFBundleOnApple()) {
+ this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+ gt->GetDirectory(cfgName));
+ } else if (gt->IsCFBundleOnApple()) {
// Create the core foundation bundle.
- this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
- gt.GetDirectory(cfgName));
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
+ gt->GetDirectory(cfgName));
}
// Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
- const cmStateEnums::TargetType targetType = gt.GetType();
+ const cmStateEnums::TargetType targetType = gt->GetType();
this->GetBuildFileStream()
<< "# Link build statements for " << cmState::GetTargetTypeName(targetType)
<< " target " << this->GetTargetName() << "\n\n";
- cmNinjaDeps emptyDeps;
- cmNinjaVars vars;
+ cmNinjaBuild linkBuild(this->LanguageLinkerRule());
+ cmNinjaVars& vars = linkBuild.Variables;
// Compute the comment.
- std::ostringstream comment;
- comment << "Link the " << this->GetVisibleTypeName() << " "
- << targetOutputReal;
+ linkBuild.Comment = "Link the ";
+ linkBuild.Comment += this->GetVisibleTypeName();
+ linkBuild.Comment += " ";
+ linkBuild.Comment += targetOutputReal;
// Compute outputs.
- cmNinjaDeps outputs;
- outputs.push_back(targetOutputReal);
+ linkBuild.Outputs.push_back(targetOutputReal);
+
+ if (this->TargetLinkLanguage == "Swift") {
+ vars["SWIFT_LIBRARY_NAME"] = [this]() -> std::string {
+ cmGeneratorTarget::Names targetNames =
+ this->GetGeneratorTarget()->GetLibraryNames(this->GetConfigName());
+ return targetNames.Base;
+ }();
+
+ vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string {
+ if (const char* name = gt->GetProperty("Swift_MODULE_NAME")) {
+ return name;
+ }
+ return gt->GetName();
+ }();
+
+ vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string {
+ std::string directory =
+ this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ if (const char* prop = this->GetGeneratorTarget()->GetProperty(
+ "Swift_MODULE_DIRECTORY")) {
+ directory = prop;
+ }
+
+ std::string name = module + ".swiftmodule";
+ if (const char* prop =
+ this->GetGeneratorTarget()->GetProperty("Swift_MODULE")) {
+ name = prop;
+ }
+
+ return this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(directory + "/" + name),
+ cmOutputConverter::SHELL);
+ }(vars["SWIFT_MODULE_NAME"]);
+
+ vars["SWIFT_OUTPUT_FILE_MAP"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(gt->GetSupportDirectory() +
+ "/output-file-map.json"),
+ cmOutputConverter::SHELL);
+
+ vars["SWIFT_SOURCES"] = [this]() -> std::string {
+ std::vector<cmSourceFile const*> sources;
+ std::stringstream oss;
+
+ this->GetGeneratorTarget()->GetObjectSources(sources,
+ this->GetConfigName());
+ cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
+ for (const auto& source : sources) {
+ oss << " "
+ << LocalGen->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)),
+ cmOutputConverter::SHELL);
+ }
+ return oss.str();
+ }();
+
+ // Since we do not perform object builds, compute the
+ // defines/flags/includes here so that they can be passed along
+ // appropriately.
+ vars["DEFINES"] = this->GetDefines("Swift");
+ vars["FLAGS"] = this->GetFlags("Swift");
+ vars["INCLUDES"] = this->GetIncludes("Swift");
+ }
// Compute specific libraries to link with.
- cmNinjaDeps explicitDeps = this->GetObjects();
- cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+ if (this->TargetLinkLanguage == "Swift") {
+ std::vector<cmSourceFile const*> sources;
+ gt->GetObjectSources(sources, this->GetConfigName());
+ for (const auto& source : sources) {
+ linkBuild.Outputs.push_back(
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source)));
+ linkBuild.ExplicitDeps.push_back(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
+ }
- if (!this->DeviceLinkObject.empty()) {
- explicitDeps.push_back(this->DeviceLinkObject);
+ linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
+ } else {
+ linkBuild.ExplicitDeps = this->GetObjects();
}
+ linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
- cmMakefile* mf = this->GetMakefile();
+ if (!this->DeviceLinkObject.empty()) {
+ linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject);
+ }
std::string frameworkPath;
std::string linkPath;
- cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
- std::string createRule = genTarget.GetCreateRuleVariable(
- this->TargetLinkLanguage, this->GetConfigName());
+ std::string createRule =
+ gt->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
@@ -826,14 +859,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
std::unique_ptr<cmLinkLineComputer> linkLineComputer(
- this->GetGlobalGenerator()->CreateLinkLineComputer(
+ globalGen->CreateLinkLineComputer(
this->GetLocalGenerator(),
this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
- localGen.GetTargetFlags(
- linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
- vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
+ localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(),
+ vars["LINK_LIBRARIES"], vars["FLAGS"],
+ vars["LINK_FLAGS"], frameworkPath, linkPath, gt);
// Add OS X version flags, if any.
if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -844,7 +877,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
"CURRENT", false);
}
- this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
+ this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]);
vars["LINK_FLAGS"] =
@@ -854,7 +887,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["LINK_PATH"] = frameworkPath + linkPath;
std::string lwyuFlags;
- if (genTarget.GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
lwyuFlags = " -Wl,--no-as-needed";
}
@@ -863,25 +896,23 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// code between the Makefile executable and library generators.
if (targetType == cmStateEnums::EXECUTABLE) {
std::string t = vars["FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
t += lwyuFlags;
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = t;
t.clear();
t += lwyuFlags;
- localGen.AddLanguageFlagsForLinking(t, &genTarget, TargetLinkLanguage,
- cfgName);
+ localGen.AddLanguageFlagsForLinking(t, gt, TargetLinkLanguage, cfgName);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
- if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
+ if (gt->HasSOName(cfgName)) {
vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
- vars["SONAME"] = this->TargetNameSO;
+ vars["SONAME"] = this->TargetNames.SharedObject;
if (targetType == cmStateEnums::SHARED_LIBRARY) {
- std::string install_dir =
- this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
+ std::string install_dir = gt->GetInstallNameDirForBuildTree(cfgName);
if (!install_dir.empty()) {
vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
install_dir, cmOutputConverter::SHELL);
@@ -891,12 +922,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
cmNinjaDeps byproducts;
- if (!this->TargetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
const std::string impLibPath = localGen.ConvertToOutputFormat(
targetOutputImplib, cmOutputConverter::SHELL);
vars["TARGET_IMPLIB"] = impLibPath;
EnsureParentDirectoryExists(impLibPath);
- if (genTarget.HasImportLibrary(cfgName)) {
+ if (gt->HasImportLibrary(cfgName)) {
byproducts.push_back(targetOutputImplib);
}
}
@@ -907,7 +938,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
std::string prefix;
std::string base;
std::string suffix;
- this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix);
+ gt->GetFullNameComponents(prefix, base, suffix);
std::string dbg_suffix = ".dbg";
// TODO: Where to document?
if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
@@ -916,12 +947,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["TARGET_PDB"] = base + suffix + dbg_suffix;
}
- const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
+ const std::string objPath = gt->GetSupportDirectory();
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
EnsureDirectoryExists(objPath);
- if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ if (globalGen->IsGCCOnWindows()) {
// ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
std::string& linkLibraries = vars["LINK_LIBRARIES"];
std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
@@ -930,8 +961,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
}
const std::vector<cmCustomCommand>* cmdLists[3] = {
- &gt.GetPreBuildCommands(), &gt.GetPreLinkCommands(),
- &gt.GetPostBuildCommands()
+ &gt->GetPreBuildCommands(), &gt->GetPreLinkCommands(),
+ &gt->GetPostBuildCommands()
};
std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
@@ -951,7 +982,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// maybe create .def file from list of objects
cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
- gt.GetModuleDefinitionInfo(this->GetConfigName());
+ gt->GetModuleDefinitionInfo(this->GetConfigName());
if (mdi && mdi->DefFileGenerated) {
std::string cmakeCommand =
this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -983,8 +1014,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
}
}
// If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR
- // for
- // the link commands.
+ // for the link commands.
if (!preLinkCmdLines.empty()) {
const std::string homeOutDir = localGen.ConvertToOutputFormat(
localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
@@ -998,92 +1028,99 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
cmNinjaVars symlinkVars;
bool const symlinkNeeded =
- (targetOutput != targetOutputReal && !gt.IsFrameworkOnApple());
+ (targetOutput != targetOutputReal && !gt->IsFrameworkOnApple());
if (!symlinkNeeded) {
vars["POST_BUILD"] = postBuildCmdLine;
} else {
vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP;
symlinkVars["POST_BUILD"] = postBuildCmdLine;
}
- cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
+
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += this->TargetLinkLanguage;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
bool const lang_supports_response =
- !(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
+ !(this->TargetLinkLanguage == "RC" ||
+ (this->TargetLinkLanguage == "CUDA" && !flag));
int commandLineLengthLimit = -1;
if (!lang_supports_response || !this->ForceResponseFile()) {
commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
- globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
+ globalGen->GetRuleCmdLength(linkBuild.Rule);
}
- const std::string rspfile = this->ConvertToNinjaPath(
- std::string("CMakeFiles/") + gt.GetName() + ".rsp");
+ linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
+ gt->GetName() + ".rsp");
// Gather order-only dependencies.
- cmNinjaDeps orderOnlyDeps;
- this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- orderOnlyDeps);
+ this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps);
// Ninja should restat after linking if and only if there are byproducts.
vars["RESTAT"] = byproducts.empty() ? "" : "1";
for (std::string const& o : byproducts) {
- this->GetGlobalGenerator()->SeenCustomCommandOutput(o);
- outputs.push_back(o);
+ globalGen->SeenCustomCommandOutput(o);
+ linkBuild.Outputs.push_back(o);
}
// Write the build statement for this target.
bool usedResponseFile = false;
- globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
- this->LanguageLinkerRule(), outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
- implicitDeps, orderOnlyDeps, vars, rspfile,
- commandLineLengthLimit, &usedResponseFile);
+ globalGen->WriteBuild(this->GetBuildFileStream(), linkBuild,
+ commandLineLengthLimit, &usedResponseFile);
this->WriteLinkRule(usedResponseFile);
if (symlinkNeeded) {
if (targetType == cmStateEnums::EXECUTABLE) {
- globalGen.WriteBuild(
- this->GetBuildFileStream(),
- "Create executable symlink " + targetOutput,
- "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput),
- /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
- emptyDeps, emptyDeps, symlinkVars);
+ cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE");
+ build.Comment = "Create executable symlink " + targetOutput;
+ build.Outputs.push_back(targetOutput);
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+ globalGen->WriteBuild(this->GetBuildFileStream(), build);
} else {
- cmNinjaDeps symlinks;
- std::string const soName =
- this->ConvertToNinjaPath(this->GetTargetFilePath(this->TargetNameSO));
+ cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
+ build.Comment = "Create library symlink " + targetOutput;
+
+ std::string const soName = this->ConvertToNinjaPath(
+ this->GetTargetFilePath(this->TargetNames.SharedObject));
// If one link has to be created.
if (targetOutputReal == soName || targetOutput == soName) {
- symlinkVars["SONAME"] = soName;
+ symlinkVars["SONAME"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ soName, cmOutputConverter::SHELL);
} else {
symlinkVars["SONAME"].clear();
- symlinks.push_back(soName);
+ build.Outputs.push_back(soName);
}
- symlinks.push_back(targetOutput);
- globalGen.WriteBuild(
- this->GetBuildFileStream(), "Create library symlink " + targetOutput,
- "CMAKE_SYMLINK_LIBRARY", symlinks,
- /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
- emptyDeps, emptyDeps, symlinkVars);
+ build.Outputs.push_back(targetOutput);
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+
+ globalGen->WriteBuild(this->GetBuildFileStream(), build);
}
}
// Add aliases for the file name and the target name.
- globalGen.AddTargetAlias(this->TargetNameOut, &gt);
- globalGen.AddTargetAlias(this->GetTargetName(), &gt);
+ globalGen->AddTargetAlias(this->TargetNames.Output, gt);
+ globalGen->AddTargetAlias(this->GetTargetName(), gt);
}
void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
{
// Write a phony output that depends on all object files.
- cmNinjaDeps outputs;
- this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
- outputs);
- cmNinjaDeps depends = this->GetObjects();
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(), "Object library " + this->GetTargetName(),
- outputs, depends);
+ {
+ cmNinjaBuild build("phony");
+ build.Comment = "Object library " + this->GetTargetName();
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
+ build.Outputs);
+ build.ExplicitDeps = this->GetObjects();
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+ }
// Add aliases for the target name.
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index 01cc8816e..14991a286 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -5,13 +5,12 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmGeneratorTarget.h"
#include "cmNinjaTargetGenerator.h"
#include <string>
#include <vector>
-class cmGeneratorTarget;
-
class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
{
public:
@@ -40,11 +39,7 @@ private:
private:
// Target name info.
- std::string TargetNameOut;
- std::string TargetNameSO;
- std::string TargetNameReal;
- std::string TargetNameImport;
- std::string TargetNamePDB;
+ cmGeneratorTarget::Names TargetNames;
std::string TargetLinkLanguage;
std::string DeviceLinkObject;
};
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 82bc5f204..2139a452d 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -9,7 +9,7 @@
#include <iterator>
#include <map>
#include <memory> // IWYU pragma: keep
-#include <sstream>
+#include <ostream>
#include <utility>
#include "cmAlgorithms.h"
@@ -19,13 +19,13 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
-#include "cmListFileCache.h" // for BT
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
#include "cmNinjaNormalTargetGenerator.h"
#include "cmNinjaUtilityTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -33,7 +33,8 @@
#include "cmSystemTools.h"
#include "cmake.h"
-cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
+std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
+ cmGeneratorTarget* target)
{
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
@@ -41,14 +42,14 @@ cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY:
- return new cmNinjaNormalTargetGenerator(target);
+ return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
case cmStateEnums::UTILITY:
case cmStateEnums::GLOBAL_TARGET:
- return new cmNinjaUtilityTargetGenerator(target);
+ return cm::make_unique<cmNinjaUtilityTargetGenerator>(target);
default:
- return nullptr;
+ return std::unique_ptr<cmNinjaTargetGenerator>();
}
}
@@ -59,13 +60,10 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
, LocalGenerator(
static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
{
- MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+ MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
}
-cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
-{
- delete this->MacOSXContentGenerator;
-}
+cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default;
cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
{
@@ -102,6 +100,12 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
return lang == "Fortran";
}
+bool cmNinjaTargetGenerator::UsePreprocessedSource(
+ std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
std::string cmNinjaTargetGenerator::LanguageDyndepRule(
const std::string& lang) const
{
@@ -451,10 +455,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
vars.ObjectDir = "$OBJECT_DIR";
vars.ObjectFileDir = "$OBJECT_FILE_DIR";
- if (lang == "Swift") {
- vars.SwiftAuxiliarySources = "$SWIFT_AUXILIARY_SOURCES";
- vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
- }
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
@@ -465,12 +465,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string flags = "$FLAGS";
std::string responseFlag;
- bool const lang_supports_response = !(lang == "RC" || lang == "CUDA");
+ bool const lang_supports_response = lang != "RC";
if (lang_supports_response && this->ForceResponseFile()) {
std::string const responseFlagVar =
"CMAKE_" + lang + "_RESPONSE_FILE_FLAG";
responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar);
- if (responseFlag.empty()) {
+ if (responseFlag.empty() && lang != "CUDA") {
responseFlag = "@";
}
}
@@ -490,15 +490,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
launcher += " ";
}
- if (explicitPP) {
- // Lookup the explicit preprocessing rule.
- std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
- std::string const ppCmd =
- this->GetMakefile()->GetRequiredDefinition(ppVar);
+ std::string const cmakeCmd =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ if (explicitPP) {
+ cmNinjaRule rule(this->LanguagePreprocessRule(lang));
// Explicit preprocessing always uses a depfile.
- std::string const ppDeptype; // no deps= for multiple outputs
- std::string const ppDepfile = "$DEP_FILE";
+ rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepFile = "$DEP_FILE";
cmRulePlaceholderExpander::RuleVariables ppVars;
ppVars.CMTargetName = vars.CMTargetName;
@@ -506,7 +506,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
ppVars.Language = vars.Language;
ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
ppVars.PreprocessedSource = "$out";
- ppVars.DependencyFile = ppDepfile.c_str();
+ ppVars.DependencyFile = rule.DepFile.c_str();
// Preprocessing uses the original source,
// compilation uses preprocessed output.
@@ -525,13 +525,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
ppVars.Includes = vars.Includes;
// If using a response file, move defines, includes, and flags into it.
- std::string ppRspFile;
- std::string ppRspContent;
if (!responseFlag.empty()) {
- ppRspFile = "$RSP_FILE";
- ppRspContent = std::string(" ") + ppVars.Defines + " " +
- ppVars.Includes + " " + ppFlags;
- ppFlags = responseFlag + ppRspFile;
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent = " ";
+ rule.RspContent += ppVars.Defines;
+ rule.RspContent += " ";
+ rule.RspContent += ppVars.Includes;
+ rule.RspContent += " ";
+ rule.RspContent += ppFlags;
+ ppFlags = responseFlag + rule.RspFile;
ppVars.Defines = "";
ppVars.Includes = "";
}
@@ -540,7 +542,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
// Rule for preprocessing source file.
std::vector<std::string> ppCmds;
- cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
+ {
+ // Lookup the explicit preprocessing rule.
+ std::string ppVar = "CMAKE_" + lang;
+ ppVar += "_PREPROCESS_SOURCE";
+ cmSystemTools::ExpandListArgument(
+ this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
+ }
for (std::string& i : ppCmds) {
i = launcher + i;
@@ -549,96 +557,93 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
}
// Run CMake dependency scanner on preprocessed output.
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ppCmds.push_back(
- cmake +
- " -E cmake_ninja_depends"
- " --tdi=" +
- tdi +
- " --pp=$out"
- " --dep=$DEP_FILE" +
- (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
-
- std::string const ppCmdLine =
- this->GetLocalGenerator()->BuildCommandLine(ppCmds);
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_depends --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --pp=$out --dep=$DEP_FILE";
+ if (needDyndep) {
+ ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
+ }
+ ppCmds.emplace_back(std::move(ccmd));
+ }
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
// Write the rule for preprocessing file of the given language.
- std::ostringstream ppComment;
- ppComment << "Rule for preprocessing " << lang << " files.";
- std::ostringstream ppDesc;
- ppDesc << "Building " << lang << " preprocessed $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc.str(),
- ppComment.str(), ppDepfile, ppDeptype, ppRspFile, ppRspContent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.Comment = "Rule for preprocessing ";
+ rule.Comment += lang;
+ rule.Comment += " files.";
+ rule.Description = "Building ";
+ rule.Description += lang;
+ rule.Description += " preprocessed $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
if (needDyndep) {
// Write the rule for ninja dyndep file generation.
- std::vector<std::string> ddCmds;
-
+ cmNinjaRule rule(this->LanguageDyndepRule(lang));
// Command line length is almost always limited -> use response file for
// dyndep rules
- std::string ddRspFile = "$out.rsp";
- std::string ddRspContent = "$in";
- std::string ddInput = "@" + ddRspFile;
-
- // Run CMake dependency scanner on preprocessed output.
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ddCmds.push_back(cmake +
- " -E cmake_ninja_dyndep"
- " --tdi=" +
- tdi +
- " --dd=$out"
- " " +
- ddInput);
-
- std::string const ddCmdLine =
- this->GetLocalGenerator()->BuildCommandLine(ddCmds);
-
- std::ostringstream ddComment;
- ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
- std::ostringstream ddDesc;
- ddDesc << "Generating " << lang << " dyndep file $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
- /*depfile*/ "",
- /*deps*/ "", ddRspFile, ddRspContent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.RspFile = "$out.rsp";
+ rule.RspContent = "$in";
+
+ // Run CMake dependency scanner on the source file (using the preprocessed
+ // source if that was performed).
+ {
+ std::vector<std::string> ddCmds;
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_dyndep --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --dd=$out ";
+ ccmd += "@";
+ ccmd += rule.RspFile;
+ ddCmds.emplace_back(std::move(ccmd));
+ }
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+ }
+ rule.Comment = "Rule to generate ninja dyndep files for ";
+ rule.Comment += lang;
+ rule.Comment += ".";
+ rule.Description = "Generating ";
+ rule.Description += lang;
+ rule.Description += " dyndep file $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
+ cmNinjaRule rule(this->LanguageCompilerRule(lang));
// If using a response file, move defines, includes, and flags into it.
- std::string rspfile;
- std::string rspcontent;
if (!responseFlag.empty()) {
- rspfile = "$RSP_FILE";
- rspcontent =
- std::string(" ") + vars.Defines + " " + vars.Includes + " " + flags;
- flags = responseFlag + rspfile;
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent = " ";
+ rule.RspContent += vars.Defines;
+ rule.RspContent += " ";
+ rule.RspContent += vars.Includes;
+ rule.RspContent += " ";
+ rule.RspContent += flags;
+ flags = responseFlag + rule.RspFile;
vars.Defines = "";
vars.Includes = "";
}
// Tell ninja dependency format so all deps can be loaded into a database
- std::string deptype;
- std::string depfile;
std::string cldeps;
if (explicitPP) {
// The explicit preprocessing step will handle dependency scanning.
} else if (this->NeedDepTypeMSVC(lang)) {
- deptype = "msvc";
- depfile.clear();
+ rule.DepType = "msvc";
+ rule.DepFile.clear();
flags += " /showIncludes";
} else if (mf->IsOn("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.
if (!mf->GetIsSourceFileTryCompile()) {
- deptype = "gcc";
- depfile = "$DEP_FILE";
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
? mf->GetSafeDefinition("CMAKE_C_COMPILER")
: mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
@@ -649,8 +654,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
cldeps += "\" \"" + cl + "\" ";
}
} else {
- deptype = "gcc";
- depfile = "$DEP_FILE";
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
std::string depfileFlags = mf->GetSafeDefinition(flagsName);
if (!depfileFlags.empty()) {
@@ -663,7 +668,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
}
vars.Flags = flags.c_str();
- vars.DependencyFile = depfile.c_str();
+ vars.DependencyFile = rule.DepFile.c_str();
// Rule for compiling object file.
std::vector<std::string> compileCmds;
@@ -671,19 +676,18 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
- std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+ const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
}
@@ -710,8 +714,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) ||
(cppcheck && *cppcheck)) {
- std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string run_iwyu = cmakeCmd;
run_iwyu += " -E __run_co_compile";
if (!compilerLauncher.empty()) {
// In __run_co_compile case the launcher command is supplied
@@ -750,8 +753,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
if (!compileCmds.empty() && !compilerLauncher.empty()) {
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(compilerLauncher, args, true);
- for (std::string& i : args) {
- i = this->LocalGenerator->EscapeForShell(i);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
}
compileCmds.front().insert(0, cmJoin(args, " ") + " ");
}
@@ -766,19 +773,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars);
}
- std::string cmdLine =
- this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(compileCmds);
// Write the rule for compiling file of the given language.
- std::ostringstream comment;
- comment << "Rule for compiling " << lang << " files.";
- std::ostringstream description;
- description << "Building " << lang << " object $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageCompilerRule(lang), cmdLine, description.str(),
- comment.str(), depfile, deptype, rspfile, rspcontent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.Comment = "Rule for compiling ";
+ rule.Comment += lang;
+ rule.Comment += " files.";
+ rule.Description = "Building ";
+ rule.Description += lang;
+ rule.Description += " object $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
void cmNinjaTargetGenerator::WriteObjectBuildStatements()
@@ -790,113 +794,141 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
<< cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
<< " target " << this->GetTargetName() << "\n\n";
- std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
- std::vector<cmSourceFile const*> customCommands;
- this->GeneratorTarget->GetCustomCommands(customCommands, config);
- for (cmSourceFile const* sf : customCommands) {
- cmCustomCommand const* cc = sf->GetCustomCommand();
- this->GetLocalGenerator()->AddCustomCommandTarget(
- cc, this->GetGeneratorTarget());
- // Record the custom commands for this target. The container is used
- // in WriteObjectBuildStatement when called in a loop below.
- this->CustomCommands.push_back(cc);
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ {
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, config);
+ for (cmSourceFile const* sf : customCommands) {
+ cmCustomCommand const* cc = sf->GetCustomCommand();
+ this->GetLocalGenerator()->AddCustomCommandTarget(
+ cc, this->GetGeneratorTarget());
+ // Record the custom commands for this target. The container is used
+ // in WriteObjectBuildStatement when called in a loop below.
+ this->CustomCommands.push_back(cc);
+ }
}
- std::vector<cmSourceFile const*> headerSources;
- this->GeneratorTarget->GetHeaderSources(headerSources, config);
- this->OSXBundleGenerator->GenerateMacOSXContentStatements(
- headerSources, this->MacOSXContentGenerator);
- std::vector<cmSourceFile const*> extraSources;
- this->GeneratorTarget->GetExtraSources(extraSources, config);
- this->OSXBundleGenerator->GenerateMacOSXContentStatements(
- extraSources, this->MacOSXContentGenerator);
- std::vector<cmSourceFile const*> externalObjects;
- this->GeneratorTarget->GetExternalObjects(externalObjects, config);
- for (cmSourceFile const* sf : externalObjects) {
- this->Objects.push_back(this->GetSourceFilePath(sf));
+ {
+ std::vector<cmSourceFile const*> headerSources;
+ this->GeneratorTarget->GetHeaderSources(headerSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ headerSources, this->MacOSXContentGenerator.get());
}
-
- cmNinjaDeps orderOnlyDeps;
- this->GetLocalGenerator()->AppendTargetDepends(
- this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
-
- // Add order-only dependencies on other files associated with the target.
- orderOnlyDeps.insert(orderOnlyDeps.end(), this->ExtraFiles.begin(),
- this->ExtraFiles.end());
-
- // Add order-only dependencies on custom command outputs.
- for (cmCustomCommand const* cc : this->CustomCommands) {
- cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
- this->GetLocalGenerator());
- 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::transform(ccbyproducts.begin(), ccbyproducts.end(),
- std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+ {
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ extraSources, this->MacOSXContentGenerator.get());
}
-
- std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
- orderOnlyDeps.erase(std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
- orderOnlyDeps.end());
-
- // The phony target must depend on at least one input or ninja will explain
- // that "output ... of phony edge with no inputs doesn't exist" and consider
- // the phony output "dirty".
- if (orderOnlyDeps.empty()) {
- // Any path that always exists will work here. It would be nice to
- // use just "." but that is not supported by Ninja < 1.7.
- std::string tgtDir;
- tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory();
- tgtDir += "/";
- tgtDir += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
- orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
+ {
+ std::vector<cmSourceFile const*> externalObjects;
+ this->GeneratorTarget->GetExternalObjects(externalObjects, config);
+ for (cmSourceFile const* sf : externalObjects) {
+ this->Objects.push_back(this->GetSourceFilePath(sf));
+ }
}
{
- cmNinjaDeps orderOnlyTarget;
- orderOnlyTarget.push_back(this->OrderDependsTargetForTarget());
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget,
- cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps);
+ cmNinjaBuild build("phony");
+ build.Comment = "Order-only phony target for " + this->GetTargetName();
+ build.Outputs.push_back(this->OrderDependsTargetForTarget());
+
+ cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(
+ this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
+
+ // Add order-only dependencies on other files associated with the target.
+ cmAppend(orderOnlyDeps, this->ExtraFiles);
+
+ // Add order-only dependencies on custom command outputs.
+ for (cmCustomCommand const* cc : this->CustomCommands) {
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
+ this->GetLocalGenerator());
+ 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::transform(ccbyproducts.begin(), ccbyproducts.end(),
+ std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+ }
+
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ orderOnlyDeps.erase(
+ std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
+ orderOnlyDeps.end());
+
+ // The phony target must depend on at least one input or ninja will explain
+ // that "output ... of phony edge with no inputs doesn't exist" and
+ // consider the phony output "dirty".
+ if (orderOnlyDeps.empty()) {
+ // Any path that always exists will work here. It would be nice to
+ // use just "." but that is not supported by Ninja < 1.7.
+ std::string tgtDir;
+ tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory();
+ tgtDir += "/";
+ tgtDir +=
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
+ }
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
- std::vector<cmSourceFile const*> objectSources;
- this->GeneratorTarget->GetObjectSources(objectSources, config);
- for (cmSourceFile const* sf : objectSources) {
- this->WriteObjectBuildStatement(sf);
+
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (cmSourceFile const* sf : objectSources) {
+ this->WriteObjectBuildStatement(sf);
+ }
}
- if (!this->DDIFiles.empty()) {
- std::string const ddComment;
- std::string const ddRule = this->LanguageDyndepRule("Fortran");
- cmNinjaDeps ddOutputs;
- cmNinjaDeps ddImplicitOuts;
- cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
- cmNinjaDeps ddImplicitDeps;
- cmNinjaDeps ddOrderOnlyDeps;
- cmNinjaVars ddVars;
+ for (auto const& langDDIFiles : this->DDIFiles) {
+ std::string const& language = langDDIFiles.first;
+ cmNinjaDeps const& ddiFiles = langDDIFiles.second;
- this->WriteTargetDependInfo("Fortran");
+ cmNinjaBuild build(this->LanguageDyndepRule(language));
+ build.Outputs.push_back(this->GetDyndepFilePath(language));
+ build.ExplicitDeps = ddiFiles;
- ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+ this->WriteTargetDependInfo(language);
// Make sure dyndep files for all our dependencies have already
- // been generated so that the 'FortranModules.json' files they
+ // been generated so that the '<LANG>Modules.json' files they
// produced as side-effects are available for us to read.
- // Ideally we should depend on the 'FortranModules.json' files
+ // Ideally we should depend on the '<LANG>Modules.json' files
// from our dependencies directly, but we don't know which of
// our dependencies produces them. Fixing this will require
// refactoring the Ninja generator to generate targets in
// dependency order so that we can collect the needed information.
this->GetLocalGenerator()->AppendTargetDepends(
- this->GeneratorTarget, ddOrderOnlyDeps, DependOnTargetArtifact);
+ this->GeneratorTarget, build.OrderOnlyDeps, DependOnTargetArtifact);
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
- ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
this->GetBuildFileStream() << "\n";
+
+ if (!this->SwiftOutputMap.empty()) {
+ std::string const mapFilePath = this->ConvertToNinjaPath(
+ this->GeneratorTarget->GetSupportDirectory() + "/output-file-map.json");
+ std::string const targetSwiftDepsPath = [this]() -> std::string {
+ cmGeneratorTarget const* target = this->GeneratorTarget;
+ if (const char* name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return name;
+ }
+ return this->ConvertToNinjaPath(target->GetSupportDirectory() + "/" +
+ target->GetName() + ".swiftdeps");
+ }();
+
+ // build the global target dependencies
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value deps(Json::objectValue);
+ deps["swift-dependencies"] = targetSwiftDepsPath;
+ this->SwiftOutputMap[""] = deps;
+
+ cmGeneratedFileStream output(mapFilePath);
+ output << this->SwiftOutputMap;
+ }
}
void cmNinjaTargetGenerator::WriteObjectBuildStatement(
@@ -912,36 +944,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
std::string const objectFileDir =
cmSystemTools::GetFilenamePath(objectFileName);
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += language;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_FLAG";
+
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+
bool const lang_supports_response =
- !(language == "RC" || language == "CUDA");
+ !(language == "RC" || (language == "CUDA" && !flag));
int const commandLineLengthLimit =
((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
- cmNinjaVars vars;
+ cmNinjaBuild objBuild(this->LanguageCompilerRule(language));
+ cmNinjaVars& vars = objBuild.Variables;
vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
vars["DEFINES"] = this->ComputeDefines(source, language);
vars["INCLUDES"] = this->ComputeIncludes(source, language);
- if (language == "Swift") {
- // The swift compiler needs all the sources besides the one being compiled
- // in order to do the type checking. List all these "auxiliary" sources.
- std::string aux_sources;
- cmGeneratorTarget::KindedSources const& sources =
- this->GeneratorTarget->GetKindedSources(this->GetConfigName());
- for (cmGeneratorTarget::SourceAndKind const& src : sources.Sources) {
- if (src.Source.Value == source) {
- continue;
- }
- aux_sources += " " + this->GetSourceFilePath(src.Source.Value);
- }
- vars["SWIFT_AUXILIARY_SOURCES"] = aux_sources;
-
- if (const char* name =
- this->GeneratorTarget->GetProperty("SWIFT_MODULE_NAME")) {
- vars["SWIFT_MODULE_NAME"] = name;
- } else {
- vars["SWIFT_MODULE_NAME"] = this->GeneratorTarget->GetName();
- }
- }
if (!this->NeedDepTypeMSVC(language)) {
bool replaceExt(false);
@@ -969,32 +989,26 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
language, sourceFileName, objectDir, objectFileName, objectFileDir,
vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
- std::string comment;
- std::string rule = this->LanguageCompilerRule(language);
-
- cmNinjaDeps outputs;
- outputs.push_back(objectFileName);
+ objBuild.Outputs.push_back(objectFileName);
// Add this object to the list of object files.
this->Objects.push_back(objectFileName);
- cmNinjaDeps explicitDeps;
- explicitDeps.push_back(sourceFileName);
+ objBuild.ExplicitDeps.push_back(sourceFileName);
- cmNinjaDeps implicitDeps;
if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
- std::vector<std::string> depList;
- cmSystemTools::ExpandListArgument(objectDeps, depList);
+ std::vector<std::string> depList =
+ cmSystemTools::ExpandedListArgument(objectDeps);
for (std::string& odi : depList) {
if (cmSystemTools::FileIsFullPath(odi)) {
odi = cmSystemTools::CollapseFullPath(odi);
}
}
std::transform(depList.begin(), depList.end(),
- std::back_inserter(implicitDeps), MapToNinjaPath());
+ std::back_inserter(objBuild.ImplicitDeps),
+ MapToNinjaPath());
}
- cmNinjaDeps orderOnlyDeps;
- orderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
+ objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
// If the source file is GENERATED and does not have a custom command
// (either attached to this source file or another one), assume that one of
@@ -1004,8 +1018,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
!source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") &&
!source->GetCustomCommand() &&
!this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
- this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
- orderOnlyDeps);
+ this->GetGlobalGenerator()->AddAssumedSourceDependencies(
+ sourceFileName, objBuild.OrderOnlyDeps);
}
// For some cases we need to generate a ninja dyndep file.
@@ -1014,89 +1028,101 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(language);
if (explicitPP) {
- std::string const ppComment;
- std::string const ppRule = this->LanguagePreprocessRule(language);
- cmNinjaDeps ppOutputs;
- cmNinjaDeps ppImplicitOuts;
- cmNinjaDeps ppExplicitDeps;
- cmNinjaDeps ppImplicitDeps;
- cmNinjaDeps ppOrderOnlyDeps;
- cmNinjaVars ppVars;
+ cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language));
std::string const ppFileName =
this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
- ppOutputs.push_back(ppFileName);
+ ppBuild.Outputs.push_back(ppFileName);
- // Move compilation dependencies to the preprocessing build statement.
- std::swap(ppExplicitDeps, explicitDeps);
- std::swap(ppImplicitDeps, implicitDeps);
- std::swap(ppOrderOnlyDeps, orderOnlyDeps);
- std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
+ ppBuild.RspFile = ppFileName + ".rsp";
- // The actual compilation will now use the preprocessed source.
- explicitDeps.push_back(ppFileName);
+ bool const compilePP = this->UsePreprocessedSource(language);
+ 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"]);
- // Preprocessing and compilation generally use the same flags.
- ppVars["FLAGS"] = vars["FLAGS"];
+ // 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"];
+ }
- // In case compilation requires flags that are incompatible with
- // preprocessing, include them here.
- std::string const postFlag =
- this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG");
- this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+ // Preprocessing and compilation generally use the same flags.
+ ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+
+ if (compilePP) {
+ // In case compilation requires flags that are incompatible with
+ // preprocessing, include them here.
+ std::string const& postFlag = this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language + "_POSTPROCESS_FLAG");
+ this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+ }
- // Move preprocessor definitions to the preprocessor build statement.
- std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+ if (compilePP) {
+ // Move preprocessor definitions to the preprocessor build statement.
+ std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
+ } else {
+ // Copy preprocessor definitions to the preprocessor build statement.
+ ppBuild.Variables["DEFINES"] = vars["DEFINES"];
+ }
// Copy include directories to the preprocessor build statement. The
// Fortran compilation build statement still needs them for the INCLUDE
// directive.
- ppVars["INCLUDES"] = vars["INCLUDES"];
+ ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
- // Prepend source file's original directory as an include directory
- // so e.g. Fortran INCLUDE statements can look for files in it.
- std::vector<std::string> sourceDirectory;
- sourceDirectory.push_back(
- cmSystemTools::GetParentDirectory(source->GetFullPath()));
+ if (compilePP) {
+ // Prepend source file's original directory as an include directory
+ // so e.g. Fortran INCLUDE statements can look for files in it.
+ std::vector<std::string> sourceDirectory;
+ sourceDirectory.push_back(
+ cmSystemTools::GetParentDirectory(source->GetFullPath()));
- std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
- sourceDirectory, this->GeneratorTarget, language, false, false,
- this->GetConfigName());
+ std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+ sourceDirectory, this->GeneratorTarget, language, false, false,
+ this->GetConfigName());
- vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+ vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+ }
// Explicit preprocessing always uses a depfile.
- ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
- ppFileName + ".d", cmOutputConverter::SHELL);
- // The actual compilation does not need a depfile because it
- // depends on the already-preprocessed source.
- vars.erase("DEP_FILE");
+ ppBuild.Variables["DEP_FILE"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectFileName + ".pp.d", 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 preprocessed source.
- ppVars["OBJ_FILE"] = objectFileName;
+ // compiling the source.
+ ppBuild.Variables["OBJ_FILE"] = objectFileName;
// Tell dependency scanner where to store dyndep intermediate results.
- std::string const ddiFile = ppFileName + ".ddi";
- ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
- ppImplicitOuts.push_back(ddiFile);
- this->DDIFiles.push_back(ddiFile);
+ std::string const ddiFile = objectFileName + ".ddi";
+ ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+ ppBuild.ImplicitOuts.push_back(ddiFile);
+ this->DDIFiles[language].push_back(ddiFile);
}
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
- ppVars);
+ ppBuild.Variables);
- std::string const ppRspFile = ppFileName + ".rsp";
-
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
- ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars, ppRspFile,
- commandLineLengthLimit);
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), ppBuild,
+ commandLineLengthLimit);
}
if (needDyndep) {
std::string const dyndep = this->GetDyndepFilePath(language);
- orderOnlyDeps.push_back(dyndep);
+ objBuild.OrderOnlyDeps.push_back(dyndep);
vars["dyndep"] = dyndep;
}
@@ -1112,21 +1138,23 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
this->SetMsvcTargetPdbVariable(vars);
- std::string const rspfile = objectFileName + ".rsp";
+ objBuild.RspFile = objectFileName + ".rsp";
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), comment, rule, outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps,
- vars, rspfile, commandLineLengthLimit);
+ if (language == "Swift") {
+ this->EmitSwiftDependencyInfo(source);
+ } else {
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(),
+ objBuild, commandLineLengthLimit);
+ }
if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
- std::vector<std::string> outputList;
- cmSystemTools::ExpandListArgument(objectOutputs, outputList);
- std::transform(outputList.begin(), outputList.end(), outputList.begin(),
- MapToNinjaPath());
- this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
- "Additional output files.",
- outputList, outputs);
+ cmNinjaBuild build("phony");
+ build.Comment = "Additional output files.";
+ build.Outputs = cmSystemTools::ExpandedListArgument(objectOutputs);
+ std::transform(build.Outputs.begin(), build.Outputs.end(),
+ build.Outputs.begin(), MapToNinjaPath());
+ build.ExplicitDeps = objBuild.Outputs;
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
}
@@ -1167,8 +1195,7 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
Json::arrayValue;
- std::vector<std::string> linked = this->GetLinkedTargetDirectories();
- for (std::string const& l : linked) {
+ for (std::string const& l : this->GetLinkedTargetDirectories()) {
tdi_linked_target_dirs.append(l);
}
@@ -1177,6 +1204,52 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
tdif << tdi;
}
+void cmNinjaTargetGenerator::EmitSwiftDependencyInfo(
+ cmSourceFile const* source)
+{
+ std::string const sourceFilePath =
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source));
+ std::string const objectFilePath =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+ std::string const swiftDepsPath = [source, objectFilePath]() -> std::string {
+ if (const char* name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return name;
+ }
+ return objectFilePath + ".swiftdeps";
+ }();
+ std::string const swiftDiaPath = [source, objectFilePath]() -> std::string {
+ if (const char* name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) {
+ return name;
+ }
+ return objectFilePath + ".dia";
+ }();
+ std::string const makeDepsPath = [this, source]() -> std::string {
+ cmLocalNinjaGenerator const* local = this->GetLocalGenerator();
+ std::string const objectFileName =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+ std::string const objectFileDir =
+ cmSystemTools::GetFilenamePath(objectFileName);
+
+ if (this->Makefile->IsOn("CMAKE_Swift_DEPFLE_EXTNSION_REPLACE")) {
+ std::string dependFileName =
+ cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d";
+ return local->ConvertToOutputFormat(objectFileDir + "/" + dependFileName,
+ cmOutputConverter::SHELL);
+ }
+ return local->ConvertToOutputFormat(objectFileName + ".d",
+ cmOutputConverter::SHELL);
+ }();
+
+ // build the source file mapping
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value entry = Json::Value(Json::objectValue);
+ entry["object"] = objectFilePath;
+ entry["dependencies"] = makeDepsPath;
+ entry["swift-dependencies"] = swiftDepsPath;
+ entry["diagnostics"] = swiftDiaPath;
+ SwiftOutputMap[sourceFilePath] = entry;
+}
+
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
@@ -1217,20 +1290,19 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileCmd =
+ const std::string& compileCmd =
this->GetMakefile()->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + language + "_COMPILE_OBJECT";
- std::string compileCmd =
+ const std::string cmdVar = "CMAKE_" + language + "_COMPILE_OBJECT";
+ const std::string& compileCmd =
this->GetMakefile()->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
}
@@ -1250,6 +1322,31 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
}
+void cmNinjaTargetGenerator::AdditionalCleanFiles()
+{
+ if (const char* prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmLocalNinjaGenerator* lg = this->LocalGenerator;
+ std::vector<std::string> cleanFiles;
+ {
+ cmGeneratorExpression ge;
+ auto cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(lg,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ false, this->GeneratorTarget, nullptr, nullptr),
+ cleanFiles);
+ }
+ std::string const& binaryDir = lg->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+ }
+ }
+}
+
void cmNinjaTargetGenerator::EnsureDirectoryExists(
const std::string& path) const
{
@@ -1257,8 +1354,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists(
cmSystemTools::MakeDirectory(path);
} else {
cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
- std::string fullPath =
- std::string(gg->GetCMakeInstance()->GetHomeOutputDirectory());
+ std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
// Also ensures their is a trailing slash.
gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
fullPath += path;
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 373c693bf..3055e18c3 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -5,11 +5,15 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cm_jsoncpp_value.h"
+
#include "cmCommonTargetGenerator.h"
#include "cmGlobalNinjaGenerator.h"
#include "cmNinjaTypes.h"
#include "cmOSXBundleGenerator.h"
+#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <vector>
@@ -25,7 +29,8 @@ class cmNinjaTargetGenerator : public cmCommonTargetGenerator
{
public:
/// Create a cmNinjaTargetGenerator according to the @a target's type.
- static cmNinjaTargetGenerator* New(cmGeneratorTarget* target);
+ static std::unique_ptr<cmNinjaTargetGenerator> New(
+ cmGeneratorTarget* target);
/// Build a NinjaTargetGenerator.
cmNinjaTargetGenerator(cmGeneratorTarget* target);
@@ -64,6 +69,7 @@ protected:
bool NeedExplicitPreprocessing(std::string const& lang) const;
std::string LanguageDyndepRule(std::string const& lang) const;
bool NeedDyndep(std::string const& lang) const;
+ bool UsePreprocessedSource(std::string const& lang) const;
std::string OrderDependsTargetForTarget();
@@ -124,12 +130,16 @@ protected:
void WriteObjectBuildStatement(cmSourceFile const* source);
void WriteTargetDependInfo(std::string const& lang);
+ void EmitSwiftDependencyInfo(cmSourceFile const* source);
+
void ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
std::string const& objectFileDir, std::string const& flags,
std::string const& defines, std::string const& includes);
+ void AdditionalCleanFiles();
+
cmNinjaDeps GetObjects() const { return this->Objects; }
void EnsureDirectoryExists(const std::string& dir) const;
@@ -151,9 +161,9 @@ protected:
};
friend struct MacOSXContentGeneratorType;
- MacOSXContentGeneratorType* MacOSXContentGenerator;
+ std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
// Properly initialized by sub-classes.
- cmOSXBundleGenerator* OSXBundleGenerator;
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
std::set<std::string> MacContentFolders;
void addPoolNinjaVariable(const std::string& pool_property,
@@ -165,7 +175,10 @@ private:
cmLocalNinjaGenerator* LocalGenerator;
/// List of object files for this target.
cmNinjaDeps Objects;
- cmNinjaDeps DDIFiles; // TODO: Make per-language.
+ // Fortran Support
+ std::map<std::string, cmNinjaDeps> DDIFiles;
+ // Swift Support
+ Json::Value SwiftOutputMap;
std::vector<cmCustomCommand const*> CustomCommands;
cmNinjaDeps ExtraFiles;
};
diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h
index 9e962f135..52c05b62c 100644
--- a/Source/cmNinjaTypes.h
+++ b/Source/cmNinjaTypes.h
@@ -8,6 +8,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
enum cmNinjaTargetDepends
@@ -20,4 +21,44 @@ typedef std::vector<std::string> cmNinjaDeps;
typedef std::set<std::string> cmNinjaOuts;
typedef std::map<std::string, std::string> cmNinjaVars;
+class cmNinjaRule
+{
+public:
+ cmNinjaRule(std::string name)
+ : Name(std::move(name))
+ {
+ }
+
+ std::string Name;
+ std::string Command;
+ std::string Description;
+ std::string Comment;
+ std::string DepFile;
+ std::string DepType;
+ std::string RspFile;
+ std::string RspContent;
+ std::string Restat;
+ bool Generator = false;
+};
+
+class cmNinjaBuild
+{
+public:
+ cmNinjaBuild() = default;
+ cmNinjaBuild(std::string rule)
+ : Rule(std::move(rule))
+ {
+ }
+
+ std::string Comment;
+ std::string Rule;
+ cmNinjaDeps Outputs;
+ cmNinjaDeps ImplicitOuts;
+ cmNinjaDeps ExplicitDeps;
+ cmNinjaDeps ImplicitDeps;
+ cmNinjaDeps OrderOnlyDeps;
+ cmNinjaVars Variables;
+ std::string RspFile;
+};
+
#endif // ! cmNinjaTypes_h
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 95fcf66f4..1225cbdf3 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -16,8 +16,10 @@
#include "cmSystemTools.h"
#include <algorithm>
+#include <array>
#include <iterator>
#include <string>
+#include <utility>
#include <vector>
cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
@@ -30,74 +32,74 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
void cmNinjaUtilityTargetGenerator::Generate()
{
- std::string utilCommandName =
- this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
+ cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
+
+ std::string utilCommandName = lg->GetCurrentBinaryDirectory();
utilCommandName += "/CMakeFiles";
utilCommandName += "/";
utilCommandName += this->GetTargetName() + ".util";
utilCommandName = this->ConvertToNinjaPath(utilCommandName);
+ cmNinjaBuild phonyBuild("phony");
std::vector<std::string> commands;
- cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName);
-
- const std::vector<cmCustomCommand>* cmdLists[2] = {
- &this->GetGeneratorTarget()->GetPreBuildCommands(),
- &this->GetGeneratorTarget()->GetPostBuildCommands()
- };
+ cmNinjaDeps deps, util_outputs(1, utilCommandName);
bool uses_terminal = false;
-
- for (unsigned i = 0; i != 2; ++i) {
- for (cmCustomCommand const& ci : *cmdLists[i]) {
- cmCustomCommandGenerator ccg(ci, this->GetConfigName(),
- this->GetLocalGenerator());
- this->GetLocalGenerator()->AppendCustomCommandDeps(ccg, deps);
- this->GetLocalGenerator()->AppendCustomCommandLines(ccg, commands);
- std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
- std::transform(ccByproducts.begin(), ccByproducts.end(),
- std::back_inserter(util_outputs), MapToNinjaPath());
- if (ci.GetUsesTerminal()) {
- uses_terminal = true;
+ {
+ std::array<std::vector<cmCustomCommand> const*, 2> const cmdLists = {
+ { &genTarget->GetPreBuildCommands(), &genTarget->GetPostBuildCommands() }
+ };
+
+ for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
+ for (cmCustomCommand const& ci : *cmdList) {
+ cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg);
+ lg->AppendCustomCommandDeps(ccg, deps);
+ lg->AppendCustomCommandLines(ccg, commands);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(util_outputs), MapToNinjaPath());
+ if (ci.GetUsesTerminal()) {
+ uses_terminal = true;
+ }
}
}
}
- std::vector<cmSourceFile*> sources;
- std::string config =
- this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
- this->GetGeneratorTarget()->GetSourceFiles(sources, config);
- for (cmSourceFile const* source : sources) {
- if (cmCustomCommand const* cc = source->GetCustomCommand()) {
- cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
- this->GetLocalGenerator());
- this->GetLocalGenerator()->AddCustomCommandTarget(
- cc, this->GetGeneratorTarget());
-
- // Depend on all custom command outputs.
- 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::transform(ccByproducts.begin(), ccByproducts.end(),
- std::back_inserter(deps), MapToNinjaPath());
+ {
+ std::string const& config =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ std::vector<cmSourceFile*> sources;
+ genTarget->GetSourceFiles(sources, config);
+ for (cmSourceFile const* source : sources) {
+ if (cmCustomCommand const* cc = source->GetCustomCommand()) {
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg);
+ lg->AddCustomCommandTarget(cc, genTarget);
+
+ // Depend on all custom command outputs.
+ 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::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(deps), MapToNinjaPath());
+ }
}
}
- this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
- outputs);
- this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- deps);
+ lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs);
+ lg->AppendTargetDepends(genTarget, deps);
if (commands.empty()) {
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Utility command for " + this->GetTargetName(), outputs, deps);
+ phonyBuild.Comment = "Utility command for " + this->GetTargetName();
+ phonyBuild.ExplicitDeps = std::move(deps);
+ gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
} else {
- std::string command = this->GetLocalGenerator()->BuildCommandLine(
- commands, "utility", this->GeneratorTarget);
- const char* echoStr =
- this->GetGeneratorTarget()->GetProperty("EchoString");
+ std::string command =
+ lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
std::string desc;
+ const char* echoStr = genTarget->GetProperty("EchoString");
if (echoStr) {
desc = echoStr;
} else {
@@ -108,18 +110,12 @@ void cmNinjaUtilityTargetGenerator::Generate()
// makefile vars.
cmSystemTools::ReplaceString(
command, "$(CMAKE_SOURCE_DIR)",
- this->GetLocalGenerator()
- ->ConvertToOutputFormat(
- this->GetLocalGenerator()->GetSourceDirectory(),
- cmOutputConverter::SHELL)
- .c_str());
+ lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL));
cmSystemTools::ReplaceString(
command, "$(CMAKE_BINARY_DIR)",
- this->GetLocalGenerator()
- ->ConvertToOutputFormat(
- this->GetLocalGenerator()->GetBinaryDirectory(),
- cmOutputConverter::SHELL)
- .c_str());
+ lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL));
cmSystemTools::ReplaceString(command, "$(ARGS)", "");
if (command.find('$') != std::string::npos) {
@@ -127,24 +123,22 @@ void cmNinjaUtilityTargetGenerator::Generate()
}
for (std::string const& util_output : util_outputs) {
- this->GetGlobalGenerator()->SeenCustomCommandOutput(util_output);
+ gg->SeenCustomCommandOutput(util_output);
}
- this->GetGlobalGenerator()->WriteCustomCommandBuild(
- command, desc, "Utility command for " + this->GetTargetName(),
- /*depfile*/ "", uses_terminal,
- /*restat*/ true, util_outputs, deps);
+ gg->WriteCustomCommandBuild(command, desc,
+ "Utility command for " + this->GetTargetName(),
+ /*depfile*/ "", /*job_pool*/ "", uses_terminal,
+ /*restat*/ true, util_outputs, deps);
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(), "", outputs,
- cmNinjaDeps(1, utilCommandName));
+ phonyBuild.ExplicitDeps.push_back(utilCommandName);
+ gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
}
// Add an alias for the logical target name regardless of what directory
// contains it. Skip this for GLOBAL_TARGET because they are meant to
// be per-directory and have one at the top-level anyway.
- if (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) {
- this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
- this->GetGeneratorTarget());
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->AddTargetAlias(this->GetTargetName(), genTarget);
}
}
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index 6857d5a27..47a8df4ef 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -54,8 +54,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
plist += this->GT->GetAppBundleDirectory(this->ConfigName,
cmGeneratorTarget::ContentLevel);
plist += "/Info.plist";
- this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName,
- plist.c_str());
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist);
this->Makefile->AddCMakeOutputFile(plist);
outpath = out;
}
@@ -90,8 +89,7 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
}
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
- this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name,
- plist.c_str());
+ this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
// Generate Versions directory only for MacOSX frameworks
if (this->Makefile->PlatformIsAppleEmbedded()) {
@@ -184,7 +182,7 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
cmGeneratorTarget::ContentLevel);
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
- this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist.c_str());
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist);
this->Makefile->AddCMakeOutputFile(plist);
}
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index 2c28fc0b7..585db423e 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -329,15 +329,13 @@ void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
void cmOrderDirectories::AddUserDirectories(
std::vector<std::string> const& extra)
{
- this->UserDirectories.insert(this->UserDirectories.end(), extra.begin(),
- extra.end());
+ cmAppend(this->UserDirectories, extra);
}
void cmOrderDirectories::AddLanguageDirectories(
std::vector<std::string> const& dirs)
{
- this->LanguageDirectories.insert(this->LanguageDirectories.end(),
- dirs.begin(), dirs.end());
+ cmAppend(this->LanguageDirectories, dirs);
}
void cmOrderDirectories::SetImplicitDirectories(
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
index 5916f7ab4..23e61d678 100644
--- a/Source/cmOrderDirectories.h
+++ b/Source/cmOrderDirectories.h
@@ -25,6 +25,8 @@ public:
cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
const char* purpose);
~cmOrderDirectories();
+ cmOrderDirectories(const cmOrderDirectories&) = delete;
+ cmOrderDirectories& operator=(const cmOrderDirectories&) = delete;
void AddRuntimeLibrary(std::string const& fullPath,
const char* soname = nullptr);
void AddLinkLibrary(std::string const& fullPath);
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 6438c7bad..deca767c6 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -27,7 +27,7 @@ public:
std::string ConvertDirectorySeparatorsForShell(
const std::string& source) const;
- ///! for existing files convert to output path and short path if spaces
+ //! for existing files convert to output path and short path if spaces
std::string ConvertToOutputForExisting(const std::string& remote,
OutputFormat format = SHELL) const;
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index 46d04a65f..f3276ecd6 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -92,6 +92,9 @@ public:
*/
~cmLBDepend() { cmDeleteAll(this->DependInformationMap); }
+ cmLBDepend(const cmLBDepend&) = delete;
+ cmLBDepend& operator=(const cmLBDepend&) = delete;
+
/**
* Set the makefile that is used as a source of classes.
*/
@@ -108,8 +111,7 @@ public:
// Now extract any include paths from the targets
std::set<std::string> uniqueIncludes;
std::vector<std::string> orderedAndUniqueIncludes;
- cmTargets& targets = this->Makefile->GetTargets();
- for (auto const& target : targets) {
+ for (auto const& target : this->Makefile->GetTargets()) {
const char* incDirProp =
target.second.GetProperty("INCLUDE_DIRECTORIES");
if (!incDirProp) {
@@ -163,7 +165,7 @@ protected:
{
cmsys::ifstream fin(info->FullPath.c_str());
if (!fin) {
- cmSystemTools::Error("error can not open ", info->FullPath.c_str());
+ cmSystemTools::Error("error can not open " + info->FullPath);
return;
}
@@ -178,7 +180,7 @@ protected:
qstart = line.find('<', 8);
// if a < is not found then move on
if (qstart == std::string::npos) {
- cmSystemTools::Error("unknown include directive ", line.c_str());
+ cmSystemTools::Error("unknown include directive " + line);
continue;
}
qend = line.find('>', qstart + 1);
@@ -290,8 +292,8 @@ protected:
// Make sure we don't visit the same file more than once.
info->DependDone = true;
- const char* path = info->FullPath.c_str();
- if (!path) {
+ const std::string& path = info->FullPath;
+ if (path.empty()) {
cmSystemTools::Error(
"Attempt to find dependencies for file without path!");
return;
@@ -353,7 +355,7 @@ protected:
if (!found) {
// Couldn't find any dependency information.
if (this->ComplainFileRegularExpression.find(info->IncludeName)) {
- cmSystemTools::Error("error cannot find dependencies for ", path);
+ cmSystemTools::Error("error cannot find dependencies for " + path);
} else {
// Destroy the name of the file so that it won't be output as a
// dependency.
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 796974cb3..521343203 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -8,13 +8,16 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cm_string_view.hxx"
class cmExecutionStatus;
-static std::string escape_arg(const std::string& arg)
+static std::string EscapeArg(const std::string& arg)
{
// replace ";" with "\;" so output argument lists will split correctly
std::string escapedArg;
@@ -27,6 +30,82 @@ static std::string escape_arg(const std::string& arg)
return escapedArg;
}
+static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+{
+ return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
+ : cmJoin(cmMakeRange(arg), ";");
+}
+
+namespace {
+
+typedef std::map<std::string, bool> options_map;
+typedef std::map<std::string, std::string> single_map;
+typedef std::map<std::string, std::vector<std::string>> multi_map;
+typedef std::set<std::string> options_set;
+
+struct UserArgumentParser : public cmArgumentParser<void>
+{
+ template <typename T, typename H>
+ void Bind(std::vector<std::string> const& names,
+ std::map<std::string, T>& ref, H duplicateKey)
+ {
+ for (std::string const& key : names) {
+ auto const it = ref.emplace(key, T{}).first;
+ bool const inserted = this->cmArgumentParser<void>::Bind(
+ cm::string_view(it->first), it->second);
+ if (!inserted) {
+ duplicateKey(key);
+ }
+ }
+ }
+};
+
+} // namespace
+
+static void PassParsedArguments(
+ const std::string& prefix, cmMakefile& makefile, const options_map& options,
+ const single_map& singleValArgs, const multi_map& multiValArgs,
+ const std::vector<std::string>& unparsed,
+ const options_set& keywordsMissingValues, bool parseFromArgV)
+{
+ for (auto const& iter : options) {
+ makefile.AddDefinition(prefix + iter.first,
+ iter.second ? "TRUE" : "FALSE");
+ }
+
+ for (auto const& iter : singleValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first, iter.second.c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ for (auto const& iter : multiValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first,
+ JoinList(iter.second, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ if (!unparsed.empty()) {
+ makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
+ JoinList(unparsed, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ makefile.AddDefinition(
+ prefix + "KEYWORDS_MISSING_VALUES",
+ cmJoin(cmMakeRange(keywordsMissingValues), ";").c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
+ }
+}
+
bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
@@ -65,11 +144,10 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// the first argument is the prefix
const std::string prefix = (*argIter++) + "_";
+ UserArgumentParser parser;
+
// define the result maps holding key/value pairs for
// options, single values and multi values
- typedef std::map<std::string, bool> options_map;
- typedef std::map<std::string, std::string> single_map;
- typedef std::map<std::string, std::vector<std::string>> multi_map;
options_map options;
single_map singleValArgs;
multi_map multiValArgs;
@@ -77,50 +155,25 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// anything else is put into a vector of unparsed strings
std::vector<std::string> unparsed;
- // remember already defined keywords
- std::set<std::string> used_keywords;
- const std::string dup_warning = "keyword defined more than once: ";
+ auto const duplicateKey = [this](std::string const& key) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::WARNING, "keyword defined more than once: " + key);
+ };
// the second argument is a (cmake) list of options without argument
std::vector<std::string> list;
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- options[iter]; // default initialize
- }
+ parser.Bind(list, options, duplicateKey);
// the third argument is a (cmake) list of single argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- singleValArgs[iter]; // default initialize
- }
+ parser.Bind(list, singleValArgs, duplicateKey);
// the fourth argument is a (cmake) list of multi argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- multiValArgs[iter]; // default initialize
- }
-
- enum insideValues
- {
- NONE,
- SINGLE,
- MULTI
- } insideValues = NONE;
- std::string currentArgName;
+ parser.Bind(list, multiValArgs, duplicateKey);
list.clear();
if (!parseFromArgV) {
@@ -155,81 +208,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
}
}
- // iterate over the arguments list and fill in the values where applicable
- for (std::string const& arg : list) {
- const options_map::iterator optIter = options.find(arg);
- if (optIter != options.end()) {
- insideValues = NONE;
- optIter->second = true;
- continue;
- }
-
- const single_map::iterator singleIter = singleValArgs.find(arg);
- if (singleIter != singleValArgs.end()) {
- insideValues = SINGLE;
- currentArgName = arg;
- continue;
- }
-
- const multi_map::iterator multiIter = multiValArgs.find(arg);
- if (multiIter != multiValArgs.end()) {
- insideValues = MULTI;
- currentArgName = arg;
- continue;
- }
-
- switch (insideValues) {
- case SINGLE:
- singleValArgs[currentArgName] = arg;
- insideValues = NONE;
- break;
- case MULTI:
- if (parseFromArgV) {
- multiValArgs[currentArgName].push_back(escape_arg(arg));
- } else {
- multiValArgs[currentArgName].push_back(arg);
- }
- break;
- default:
- if (parseFromArgV) {
- unparsed.push_back(escape_arg(arg));
- } else {
- unparsed.push_back(arg);
- }
- break;
- }
- }
+ std::vector<std::string> keywordsMissingValues;
- // now iterate over the collected values and update their definition
- // within the current scope. undefine if necessary.
+ parser.Parse(list, &unparsed, &keywordsMissingValues);
- for (auto const& iter : options) {
- this->Makefile->AddDefinition(prefix + iter.first,
- iter.second ? "TRUE" : "FALSE");
- }
- for (auto const& iter : singleValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(prefix + iter.first, iter.second.c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- for (auto const& iter : multiValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(
- prefix + iter.first, cmJoin(cmMakeRange(iter.second), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- if (!unparsed.empty()) {
- this->Makefile->AddDefinition(prefix + "UNPARSED_ARGUMENTS",
- cmJoin(cmMakeRange(unparsed), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
- }
+ PassParsedArguments(
+ prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed,
+ options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
+ parseFromArgV);
return true;
}
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 0a234c52e..ec4013629 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -145,7 +145,7 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy,
} else {
std::ostringstream e;
e << defaultVar << " has value \"" << defaultValue
- << "\" but must be \"OLD\", \"NEW\", or \"\" (empty).";
+ << R"(" but must be "OLD", "NEW", or "" (empty).)";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
@@ -299,7 +299,7 @@ bool cmPolicies::GetPolicyID(const char* id, cmPolicies::PolicyID& pid)
return stringToId(id, pid);
}
-///! return a warning string for a given policy
+//! return a warning string for a given policy
std::string cmPolicies::GetPolicyWarning(cmPolicies::PolicyID id)
{
std::ostringstream msg;
@@ -333,7 +333,7 @@ std::string cmPolicies::GetPolicyDeprecatedWarning(cmPolicies::PolicyID id)
return msg.str();
}
-///! return an error string for when a required policy is unspecified
+//! return an error string for when a required policy is unspecified
std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
{
std::ostringstream error;
@@ -359,7 +359,7 @@ std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
return error.str();
}
-///! Get the default status for a policy
+//! Get the default status for a policy
cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(
cmPolicies::PolicyID /*unused*/)
{
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 314f27dc5..b70511980 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -261,7 +261,25 @@ class cmMakefile;
3, 14, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0088, \
"FindBISON runs bison in CMAKE_CURRENT_BINARY_DIR when executing.", \
- 3, 14, 0, cmPolicies::WARN)
+ 3, 14, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0089, \
+ "Compiler id for IBM Clang-based XL compilers is now XLClang.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0090, \
+ "export(PACKAGE) does not populate package registry by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0091, \
+ "MSVC runtime library flags are selected by an abstraction.", 3, 15, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0092, \
+ "MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0093, "FindBoost reports Boost_VERSION in x.y.z format.", \
+ 3, 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0094, \
+ "FindPython3, FindPython2 and FindPyton use " \
+ "LOCATION for lookup strategy.", \
+ 3, 15, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -326,27 +344,27 @@ public:
CMPCOUNT
};
- ///! convert a string policy ID into a number
+ //! convert a string policy ID into a number
static bool GetPolicyID(const char* id, /* out */ cmPolicies::PolicyID& pid);
- ///! Get the default status for a policy
+ //! Get the default status for a policy
static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
- ///! Set a policy level for this listfile
+ //! Set a policy level for this listfile
static bool ApplyPolicyVersion(cmMakefile* mf,
std::string const& version_min,
std::string const& version_max);
static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer,
unsigned int minorVer, unsigned int patchVer);
- ///! return a warning string for a given policy
+ //! return a warning string for a given policy
static std::string GetPolicyWarning(cmPolicies::PolicyID id);
static std::string GetPolicyDeprecatedWarning(cmPolicies::PolicyID id);
- ///! return an error string for when a required policy is unspecified
+ //! return an error string for when a required policy is unspecified
static std::string GetRequiredPolicyError(cmPolicies::PolicyID id);
- ///! return an error string for when a required policy is unspecified
+ //! return an error string for when a required policy is unspecified
static std::string GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id);
/** Represent a set of policy values. */
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 2fe9fe8b9..8615ecc8d 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -25,6 +25,10 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
return false;
}
+ if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE_BEFORE")) {
+ return false;
+ }
+
std::string const& projectName = args[0];
this->Makefile->SetProjectName(projectName);
@@ -214,7 +218,7 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
}
cmsys::RegularExpression vx(
- "^([0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?)?$");
+ R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
if (!vx.find(version)) {
std::string e = "VERSION \"" + version + "\" format invalid.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
@@ -319,21 +323,41 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
languages.emplace_back("CXX");
}
this->Makefile->EnableLanguage(languages, false);
- std::string extraInclude = "CMAKE_PROJECT_" + projectName + "_INCLUDE";
- const char* include = this->Makefile->GetDefinition(extraInclude);
- if (include) {
- bool readit = this->Makefile->ReadDependentFile(include);
- if (!readit && !cmSystemTools::GetFatalErrorOccured()) {
- std::string m = "could not find file:\n"
- " ";
- m += include;
- this->SetError(m);
- return false;
- }
+
+ if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE")) {
+ return false;
}
+
+ if (!this->IncludeByVariable("CMAKE_PROJECT_" + projectName + "_INCLUDE")) {
+ return false;
+ }
+
return true;
}
+bool cmProjectCommand::IncludeByVariable(const std::string& variable)
+{
+ const char* include = this->Makefile->GetDefinition(variable);
+ if (!include) {
+ return true;
+ }
+
+ const bool readit = this->Makefile->ReadDependentFile(include);
+ if (readit) {
+ return true;
+ }
+
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+
+ std::string m = "could not find file:\n"
+ " ";
+ m += include;
+ this->SetError(m);
+ return false;
+}
+
void cmProjectCommand::TopLevelCMakeVarCondSet(const char* const name,
const char* const value)
{
diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h
index 365d4487a..f1d03e71d 100644
--- a/Source/cmProjectCommand.h
+++ b/Source/cmProjectCommand.h
@@ -36,6 +36,7 @@ public:
cmExecutionStatus& status) override;
private:
+ bool IncludeByVariable(const std::string& variable);
void TopLevelCMakeVarCondSet(const char* name, const char* value);
};
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
index 6acc7ef86..9a764c678 100644
--- a/Source/cmQTWrapCPPCommand.cxx
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -4,6 +4,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -29,13 +30,13 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
// Create a rule for all sources listed.
- for (std::vector<std::string>::const_iterator j = (args.begin() + 2);
- j != args.end(); ++j) {
- cmSourceFile* curr = this->Makefile->GetSource(*j);
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should wrap the class
if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
// Compute the name of the file to generate.
- std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
std::string newName = this->Makefile->GetCurrentBinaryDirectory();
newName += "/moc_";
newName += srcName;
@@ -47,8 +48,8 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
// Compute the name of the header from which to generate the file.
std::string hname;
- if (cmSystemTools::FileIsFullPath(*j)) {
- hname = *j;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ hname = arg;
} else {
if (curr && curr->GetIsGenerated()) {
hname = this->Makefile->GetCurrentBinaryDirectory();
@@ -56,7 +57,7 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
hname = this->Makefile->GetCurrentSourceDirectory();
}
hname += "/";
- hname += *j;
+ hname += arg;
}
// Append the generated source file to the list.
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
index 43b1fb9b6..2223e2d82 100644
--- a/Source/cmQTWrapUICommand.cxx
+++ b/Source/cmQTWrapUICommand.cxx
@@ -4,6 +4,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -33,13 +34,13 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
// Create rules for all sources listed.
- for (std::vector<std::string>::const_iterator j = (args.begin() + 3);
- j != args.end(); ++j) {
- cmSourceFile* curr = this->Makefile->GetSource(*j);
+ for (std::string const& arg : cmMakeRange(args).advance(3)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should wrap the class
if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
// Compute the name of the files to generate.
- std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
std::string hName = this->Makefile->GetCurrentBinaryDirectory();
hName += "/";
hName += srcName;
@@ -55,8 +56,8 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
// Compute the name of the ui file from which to generate others.
std::string uiName;
- if (cmSystemTools::FileIsFullPath(*j)) {
- uiName = *j;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ uiName = arg;
} else {
if (curr && curr->GetIsGenerated()) {
uiName = this->Makefile->GetCurrentBinaryDirectory();
@@ -64,7 +65,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
uiName = this->Makefile->GetCurrentSourceDirectory();
}
uiName += "/";
- uiName += *j;
+ uiName += arg;
}
// create the list of headers
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
index 653caf75b..3683eddda 100644
--- a/Source/cmQtAutoGen.cxx
+++ b/Source/cmQtAutoGen.cxx
@@ -1,23 +1,19 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
+
#include "cmAlgorithms.h"
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
#include "cmSystemTools.h"
-
+#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
-#include <iterator>
+#include <array>
#include <sstream>
#include <utility>
-// - Static variables
-
-std::string const genNameGen = "AutoGen";
-std::string const genNameMoc = "AutoMoc";
-std::string const genNameUic = "AutoUic";
-std::string const genNameRcc = "AutoRcc";
-
// - Static functions
/// @brief Merges newOpts into baseOpts
@@ -72,32 +68,52 @@ void MergeOptions(std::vector<std::string>& baseOpts,
}
}
// Append options
- baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end());
+ cmAppend(baseOpts, extraOpts);
}
// - Class definitions
-std::string const cmQtAutoGen::ListSep = "<<<S>>>";
unsigned int const cmQtAutoGen::ParallelMax = 64;
+std::string const cmQtAutoGen::ListSep = "<<<S>>>";
-std::string const& cmQtAutoGen::GeneratorName(GeneratorT type)
+std::string const& cmQtAutoGen::GeneratorName(GenT genType)
{
- switch (type) {
- case GeneratorT::GEN:
- return genNameGen;
- case GeneratorT::MOC:
- return genNameMoc;
- case GeneratorT::UIC:
- return genNameUic;
- case GeneratorT::RCC:
- return genNameRcc;
+ static const std::string AutoGen("AutoGen");
+ static const std::string AutoMoc("AutoMoc");
+ static const std::string AutoUic("AutoUic");
+ static const std::string AutoRcc("AutoRcc");
+
+ switch (genType) {
+ case GenT::GEN:
+ return AutoGen;
+ case GenT::MOC:
+ return AutoMoc;
+ case GenT::UIC:
+ return AutoUic;
+ case GenT::RCC:
+ return AutoRcc;
}
- return genNameGen;
+ return AutoGen;
}
-std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType)
+std::string const& cmQtAutoGen::GeneratorNameUpper(GenT genType)
{
- return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType));
+ static const std::string AUTOGEN("AUTOGEN");
+ static const std::string AUTOMOC("AUTOMOC");
+ static const std::string AUTOUIC("AUTOUIC");
+ static const std::string AUTORCC("AUTORCC");
+
+ switch (genType) {
+ case GenT::GEN:
+ return AUTOGEN;
+ case GenT::MOC:
+ return AUTOMOC;
+ case GenT::UIC:
+ return AUTOUIC;
+ case GenT::RCC:
+ return AUTORCC;
+ }
+ return AUTOGEN;
}
std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
@@ -137,13 +153,21 @@ std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
std::string cmQtAutoGen::Quoted(std::string const& text)
{
- static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
- "\b", "\\b", "\f", "\\f", "\n", "\\n",
- "\r", "\\r", "\t", "\\t", "\v", "\\v" };
+ const std::array<std::pair<const char*, const char*>, 9> replaces = {
+ { { "\\", "\\\\" },
+ { "\"", "\\\"" },
+ { "\a", "\\a" },
+ { "\b", "\\b" },
+ { "\f", "\\f" },
+ { "\n", "\\n" },
+ { "\r", "\\r" },
+ { "\t", "\\t" },
+ { "\v", "\\v" } }
+ };
std::string res = text;
- for (const char* const* it = cm::cbegin(rep); it != cm::cend(rep); it += 2) {
- cmSystemTools::ReplaceString(res, *it, *(it + 1));
+ for (auto const& pair : replaces) {
+ cmSystemTools::ReplaceString(res, pair.first, pair.second);
}
res = '"' + res;
res += '"';
@@ -170,11 +194,11 @@ std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
std::string cmQtAutoGen::SubDirPrefix(std::string const& filename)
{
- std::string res(cmSystemTools::GetFilenamePath(filename));
- if (!res.empty()) {
- res += '/';
+ std::string::size_type slash_pos = filename.rfind('/');
+ if (slash_pos == std::string::npos) {
+ return std::string();
}
- return res;
+ return filename.substr(0, slash_pos + 1);
}
std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename,
@@ -216,8 +240,8 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
}
-void cmQtAutoGen::RccListParseContent(std::string const& content,
- std::vector<std::string>& files)
+static void RccListParseContent(std::string const& content,
+ std::vector<std::string>& files)
{
cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
@@ -234,10 +258,10 @@ void cmQtAutoGen::RccListParseContent(std::string const& content,
}
}
-bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
- std::string const& rccStdErr,
- std::vector<std::string>& files,
- std::string& error)
+static bool RccListParseOutput(std::string const& rccStdOut,
+ std::string const& rccStdErr,
+ std::vector<std::string>& files,
+ std::string& error)
{
// Lambda to strip CR characters
auto StripCR = [](std::string& line) {
@@ -284,11 +308,103 @@ bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
return true;
}
-void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir,
- std::vector<std::string>& files)
+cmQtAutoGen::RccLister::RccLister() = default;
+
+cmQtAutoGen::RccLister::RccLister(std::string rccExecutable,
+ std::vector<std::string> listOptions)
+ : RccExcutable_(std::move(rccExecutable))
+ , ListOptions_(std::move(listOptions))
+{
+}
+
+bool cmQtAutoGen::RccLister::list(std::string const& qrcFile,
+ std::vector<std::string>& files,
+ std::string& error, bool verbose) const
{
+ error.clear();
+
+ if (!cmSystemTools::FileExists(qrcFile, true)) {
+ error = "The resource file ";
+ error += Quoted(qrcFile);
+ error += " does not exist.";
+ return false;
+ }
+
+ // Run rcc list command in the directory of the qrc file with the pathless
+ // qrc file name argument. This way rcc prints relative paths.
+ // This avoids issues on Windows when the qrc file is in a path that
+ // contains non-ASCII characters.
+ std::string const fileDir = cmSystemTools::GetFilenamePath(qrcFile);
+
+ if (!this->RccExcutable_.empty() &&
+ cmSystemTools::FileExists(this->RccExcutable_, true) &&
+ !this->ListOptions_.empty()) {
+
+ bool result = false;
+ int retVal = 0;
+ std::string rccStdOut;
+ std::string rccStdErr;
+ {
+ std::vector<std::string> cmd;
+ cmd.emplace_back(this->RccExcutable_);
+ cmAppend(cmd, this->ListOptions_);
+ cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile));
+
+ // Log command
+ if (verbose) {
+ std::string msg = "Running command:\n";
+ msg += QuotedCommand(cmd);
+ msg += '\n';
+ cmSystemTools::Stdout(msg);
+ }
+
+ result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ }
+ if (!result || retVal) {
+ error = "The rcc list process failed for ";
+ error += Quoted(qrcFile);
+ error += "\n";
+ if (!rccStdOut.empty()) {
+ error += rccStdOut;
+ error += "\n";
+ }
+ if (!rccStdErr.empty()) {
+ error += rccStdErr;
+ error += "\n";
+ }
+ return false;
+ }
+ if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ return false;
+ }
+ } else {
+ // We can't use rcc for the file listing.
+ // Read the qrc file content into string and parse it.
+ {
+ std::string qrcContents;
+ {
+ cmsys::ifstream ifs(qrcFile.c_str());
+ if (ifs) {
+ std::ostringstream osst;
+ osst << ifs.rdbuf();
+ qrcContents = osst.str();
+ } else {
+ error = "The resource file ";
+ error += Quoted(qrcFile);
+ error += " is not readable\n";
+ return false;
+ }
+ }
+ // Parse string content
+ RccListParseContent(qrcContents, files);
+ }
+ }
+
+ // Convert relative paths to absolute paths
for (std::string& entry : files) {
- std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry);
- entry = std::move(tmp);
+ entry = cmSystemTools::CollapseFullPath(entry, fileDir);
}
+ return true;
}
diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h
index 96d1946f0..9c5212952 100644
--- a/Source/cmQtAutoGen.h
+++ b/Source/cmQtAutoGen.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
@@ -14,20 +15,6 @@
class cmQtAutoGen
{
public:
- /// @brief Nested lists separator
- static std::string const ListSep;
- /// @brief Maximum number of parallel threads/processes in a generator
- static unsigned int const ParallelMax;
-
- /// @brief AutoGen generator type
- enum class GeneratorT
- {
- GEN, // General
- MOC,
- UIC,
- RCC
- };
-
/// @brief Integer version
struct IntegerVersion
{
@@ -54,11 +41,34 @@ public:
}
};
+ class CompilerFeatures
+ {
+ public:
+ bool Evaluated = false;
+ std::string HelpOutput;
+ std::vector<std::string> ListOptions;
+ };
+ typedef std::shared_ptr<CompilerFeatures> CompilerFeaturesHandle;
+
+ /// @brief AutoGen generator type
+ enum class GenT
+ {
+ GEN, // AUTOGEN
+ MOC, // AUTOMOC
+ UIC, // AUTOUIC
+ RCC // AUTORCC
+ };
+
+ /// @brief Nested lists separator
+ static std::string const ListSep;
+ /// @brief Maximum number of parallel threads/processes in a generator
+ static unsigned int const ParallelMax;
+
public:
/// @brief Returns the generator name
- static std::string const& GeneratorName(GeneratorT genType);
+ static std::string const& GeneratorName(GenT genType);
/// @brief Returns the generator name in upper case
- static std::string GeneratorNameUpper(GeneratorT genType);
+ static std::string const& GeneratorNameUpper(GenT genType);
/// @brief Returns a string with the requested tool names
static std::string Tools(bool moc, bool uic, bool rcc);
@@ -85,21 +95,44 @@ public:
std::vector<std::string> const& newOpts,
bool isQt5);
- /// @brief Parses the content of a qrc file
- ///
- /// Use when rcc does not support the "--list" option
- static void RccListParseContent(std::string const& content,
- std::vector<std::string>& files);
-
- /// @brief Parses the output of the "rcc --list ..." command
- static bool RccListParseOutput(std::string const& rccStdOut,
- std::string const& rccStdErr,
- std::vector<std::string>& files,
- std::string& error);
-
- /// @brief Converts relative qrc entry paths to full paths
- static void RccListConvertFullPath(std::string const& qrcFileDir,
- std::vector<std::string>& files);
+ /** @class RccLister
+ * @brief Lists files in qrc resource files
+ */
+ class RccLister
+ {
+ public:
+ RccLister();
+ RccLister(std::string rccExecutable, std::vector<std::string> listOptions);
+
+ //! The rcc executable
+ std::string const& RccExcutable() const { return RccExcutable_; }
+ void SetRccExecutable(std::string const& rccExecutable)
+ {
+ RccExcutable_ = rccExecutable;
+ }
+
+ //! The rcc executable list options
+ std::vector<std::string> const& ListOptions() const
+ {
+ return ListOptions_;
+ }
+ void SetListOptions(std::vector<std::string> const& listOptions)
+ {
+ ListOptions_ = listOptions;
+ }
+
+ /**
+ * @brief Lists a files in the qrcFile
+ * @arg files The file names are appended to this list
+ * @arg error contains the error message when the function fails
+ */
+ bool list(std::string const& qrcFile, std::vector<std::string>& files,
+ std::string& error, bool verbose = false) const;
+
+ private:
+ std::string RccExcutable_;
+ std::vector<std::string> ListOptions_;
+ };
};
#endif
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 3ad91eec6..ef8a56b3b 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -20,6 +20,24 @@
#include <memory>
#include <utility>
+cmQtAutoGenGlobalInitializer::Keywords::Keywords()
+ : AUTOMOC("AUTOMOC")
+ , AUTOUIC("AUTOUIC")
+ , AUTORCC("AUTORCC")
+ , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE")
+ , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE")
+ , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE")
+ , SKIP_AUTOGEN("SKIP_AUTOGEN")
+ , SKIP_AUTOMOC("SKIP_AUTOMOC")
+ , SKIP_AUTOUIC("SKIP_AUTOUIC")
+ , SKIP_AUTORCC("SKIP_AUTORCC")
+ , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS")
+ , AUTORCC_OPTIONS("AUTORCC_OPTIONS")
+ , qrc("qrc")
+ , ui("ui")
+{
+}
+
cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators)
{
@@ -74,16 +92,16 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
continue;
}
- bool const moc = target->GetPropertyAsBool("AUTOMOC");
- bool const uic = target->GetPropertyAsBool("AUTOUIC");
- bool const rcc = target->GetPropertyAsBool("AUTORCC");
+ bool const moc = target->GetPropertyAsBool(kw().AUTOMOC);
+ bool const uic = target->GetPropertyAsBool(kw().AUTOUIC);
+ bool const rcc = target->GetPropertyAsBool(kw().AUTORCC);
if (moc || uic || rcc) {
std::string const mocExec =
- target->GetSafeProperty("AUTOMOC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE);
std::string const uicExec =
- target->GetSafeProperty("AUTOUIC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE);
std::string const rccExec =
- target->GetSafeProperty("AUTORCC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
// We support Qt4, Qt5 and Qt6
auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
@@ -185,19 +203,16 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
}
}
-bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
+cmQtAutoGen::CompilerFeaturesHandle
+cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
std::string const& generator, std::string const& executable,
- std::string& error, std::string* output)
+ std::string& error)
{
- // Check if we have cached output
+ // Check if we have cached features
{
- auto it = this->ExecutableTestOutputs_.find(executable);
- if (it != this->ExecutableTestOutputs_.end()) {
- // Return output on demand
- if (output != nullptr) {
- *output = it->second;
- }
- return true;
+ auto it = this->CompilerFeatures_.find(executable);
+ if (it != this->CompilerFeatures_.end()) {
+ return it->second;
}
}
@@ -208,7 +223,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += "\" executable ";
error += cmQtAutoGen::Quoted(executable);
error += " does not exist.";
- return false;
+ return cmQtAutoGen::CompilerFeaturesHandle();
}
// Test the executable
@@ -216,7 +231,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
{
std::string stdErr;
std::vector<std::string> command;
- command.push_back(executable);
+ command.emplace_back(executable);
command.emplace_back("-h");
int retVal = 0;
const bool runResult = cmSystemTools::RunSingleCommand(
@@ -232,19 +247,19 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += stdOut;
error += "\n";
error += stdErr;
- return false;
+ return cmQtAutoGen::CompilerFeaturesHandle();
}
}
- // Return executable output on demand
- if (output != nullptr) {
- *output = stdOut;
- }
+ // Create valid handle
+ cmQtAutoGen::CompilerFeaturesHandle res =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ res->HelpOutput = std::move(stdOut);
- // Register executable and output
- this->ExecutableTestOutputs_.emplace(executable, std::move(stdOut));
+ // Register compiler features
+ this->CompilerFeatures_.emplace(executable, res);
- return true;
+ return res;
}
bool cmQtAutoGenGlobalInitializer::generate()
diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h
index 74184a0d5..d56153ab7 100644
--- a/Source/cmQtAutoGenGlobalInitializer.h
+++ b/Source/cmQtAutoGenGlobalInitializer.h
@@ -5,6 +5,8 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmQtAutoGen.h"
+
#include <map>
#include <memory> // IWYU pragma: keep
#include <string>
@@ -18,10 +20,39 @@ class cmQtAutoGenInitializer;
class cmQtAutoGenGlobalInitializer
{
public:
+ /// @brief Collection of QtAutogen related keywords
+ class Keywords
+ {
+ public:
+ Keywords();
+
+ std::string AUTOMOC;
+ std::string AUTOUIC;
+ std::string AUTORCC;
+
+ std::string AUTOMOC_EXECUTABLE;
+ std::string AUTOUIC_EXECUTABLE;
+ std::string AUTORCC_EXECUTABLE;
+
+ std::string SKIP_AUTOGEN;
+ std::string SKIP_AUTOMOC;
+ std::string SKIP_AUTOUIC;
+ std::string SKIP_AUTORCC;
+
+ std::string AUTOUIC_OPTIONS;
+ std::string AUTORCC_OPTIONS;
+
+ std::string qrc;
+ std::string ui;
+ };
+
+public:
cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators);
~cmQtAutoGenGlobalInitializer();
+ Keywords const& kw() const { return Keywords_; };
+
bool generate();
private:
@@ -39,15 +70,17 @@ private:
void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
std::string const& targetName);
- bool GetExecutableTestOutput(std::string const& generator,
- std::string const& executable,
- std::string& error, std::string* output);
+ cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures(
+ 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_;
- std::unordered_map<std::string, std::string> ExecutableTestOutputs_;
+ std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>
+ CompilerFeatures_;
+ Keywords const Keywords_;
};
#endif
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 614a88bde..9985f93eb 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -7,7 +7,6 @@
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
-#include "cmDuration.h"
#include "cmFilePathChecksum.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -19,14 +18,14 @@
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
-#include "cmProcessOutput.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
#include "cmSourceGroup.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
-#include "cmsys/FStream.hxx"
+#include "cmake.h"
#include "cmsys/SystemInformation.hxx"
#include <algorithm>
@@ -34,27 +33,11 @@
#include <deque>
#include <map>
#include <set>
-#include <sstream>
#include <string>
-#include <type_traits>
+#include <unordered_set>
#include <utility>
#include <vector>
-std::string GetQtExecutableTargetName(
- const cmQtAutoGen::IntegerVersion& qtVersion, std::string const& executable)
-{
- if (qtVersion.Major == 6) {
- return ("Qt6::" + executable);
- }
- if (qtVersion.Major == 5) {
- return ("Qt5::" + executable);
- }
- if (qtVersion.Major == 4) {
- return ("Qt4::" + executable);
- }
- return ("");
-}
-
static std::size_t GetParallelCPUCount()
{
static std::size_t count = 0;
@@ -69,64 +52,6 @@ static std::size_t GetParallelCPUCount()
return count;
}
-static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
- cmQtAutoGen::GeneratorT genType)
-{
- cmSourceGroup* sourceGroup = nullptr;
- // Acquire source group
- {
- std::string property;
- std::string groupName;
- {
- std::array<std::string, 2> props;
- // Use generator specific group name
- switch (genType) {
- case cmQtAutoGen::GeneratorT::MOC:
- props[0] = "AUTOMOC_SOURCE_GROUP";
- break;
- case cmQtAutoGen::GeneratorT::RCC:
- props[0] = "AUTORCC_SOURCE_GROUP";
- break;
- default:
- props[0] = "AUTOGEN_SOURCE_GROUP";
- break;
- }
- props[1] = "AUTOGEN_SOURCE_GROUP";
- for (std::string& prop : props) {
- const char* propName = makefile->GetState()->GetGlobalProperty(prop);
- if ((propName != nullptr) && (*propName != '\0')) {
- groupName = propName;
- property = std::move(prop);
- break;
- }
- }
- }
- // Generate a source group on demand
- if (!groupName.empty()) {
- sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
- if (sourceGroup == nullptr) {
- std::ostringstream ost;
- ost << cmQtAutoGen::GeneratorNameUpper(genType);
- ost << ": " << property;
- ost << ": Could not find or create the source group ";
- ost << cmQtAutoGen::Quoted(groupName);
- cmSystemTools::Error(ost.str());
- return false;
- }
- }
- }
- if (sourceGroup != nullptr) {
- sourceGroup->AddGroupFile(fileName);
- }
- return true;
-}
-
-static void AddCleanFile(cmMakefile* makefile, std::string const& fileName)
-{
- makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(),
- false);
-}
-
static std::string FileProjectRelativePath(cmMakefile* makefile,
std::string const& fileName)
{
@@ -147,7 +72,8 @@ static std::string FileProjectRelativePath(cmMakefile* makefile,
return res;
}
-/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its
+/**
+ * Tests if targetDepend is a STATIC_LIBRARY and if any of its
* recursive STATIC_LIBRARY dependencies depends on targetOrigin
* (STATIC_LIBRARY cycle).
*/
@@ -343,6 +269,26 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
+ // Check status of policy CMP0071
+ {
+ cmPolicies::PolicyStatus const CMP0071_status =
+ makefile->GetPolicyStatus(cmPolicies::CMP0071);
+ switch (CMP0071_status) {
+ case cmPolicies::WARN:
+ this->CMP0071Warn = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // Ignore GENERATED file
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Process GENERATED file
+ this->CMP0071Accept = true;
+ break;
+ }
+ }
+
// Common directories
{
// Collapsed current binary directory
@@ -368,7 +314,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
// Cleanup build directory
- AddCleanFile(makefile, this->Dir.Build);
+ this->AddCleanFile(this->Dir.Build);
// Working directory
this->Dir.Work = cbd;
@@ -392,23 +338,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Moc, Uic and _autogen target settings
- if (this->Moc.Enabled || this->Uic.Enabled) {
+ if (this->MocOrUicEnabled()) {
// Init moc specific settings
if (this->Moc.Enabled && !InitMoc()) {
return false;
}
// Init uic specific settings
- if (this->Uic.Enabled) {
- if (InitUic()) {
- auto* uicTarget = makefile->FindTargetToUse(
- GetQtExecutableTargetName(this->QtVersion, "uic"));
- if (uicTarget != nullptr) {
- this->AutogenTarget.DependTargets.insert(uicTarget);
- }
- } else {
- return false;
- }
+ if (this->Uic.Enabled && !InitUic()) {
+ return false;
}
// Autogen target name
@@ -437,11 +375,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
std::string& filename = this->AutogenTarget.ConfigSettingsFile[cfg];
filename =
AppendFilenameSuffix(this->AutogenTarget.SettingsFile, "_" + cfg);
- AddCleanFile(makefile, filename);
+ this->AddCleanFile(filename);
}
} else {
- AddCleanFile(makefile, this->AutogenTarget.SettingsFile);
+ this->AddCleanFile(this->AutogenTarget.SettingsFile);
}
+
+ this->AutogenTarget.ParseCacheFile = this->Dir.Info;
+ this->AutogenTarget.ParseCacheFile += "/ParseCache.txt";
+ this->AddCleanFile(this->AutogenTarget.ParseCacheFile);
}
// Autogen target: Compute user defined dependencies
@@ -449,12 +391,6 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
this->AutogenTarget.DependOrigin =
this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
- auto* mocTarget = makefile->FindTargetToUse(
- GetQtExecutableTargetName(this->QtVersion, "moc"));
- if (mocTarget != nullptr) {
- this->AutogenTarget.DependTargets.insert(mocTarget);
- }
-
std::string const deps =
this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
if (!deps.empty()) {
@@ -471,6 +407,19 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
}
+
+ // CMAKE_AUTOMOC_RELAXED_MODE deprecation warning
+ if (this->Moc.Enabled) {
+ if (cmSystemTools::IsOn(
+ makefile->GetDefinition("CMAKE_AUTOMOC_RELAXED_MODE"))) {
+ std::string msg = "AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
+ "deprecated an will be removed in the future. ";
+ msg += "Consider disabling it and converting the target ";
+ msg += this->Target->GetName();
+ msg += " to regular mode.";
+ makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
+ }
+ }
}
// Init rcc specific settings
@@ -479,8 +428,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Add autogen include directory to the origin target INCLUDE_DIRECTORIES
- if (this->Moc.Enabled || this->Uic.Enabled ||
- (this->Rcc.Enabled && this->MultiConfig)) {
+ if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
this->Target->AddIncludeDirectory(this->Dir.Include, true);
}
@@ -490,7 +438,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Create autogen target
- if ((this->Moc.Enabled || this->Uic.Enabled) && !this->InitAutogenTarget()) {
+ if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
return false;
}
@@ -575,7 +523,18 @@ bool cmQtAutoGenInitializer::InitMoc()
}
// Moc executable
- return GetMocExecutable();
+ {
+ if (!this->GetQtExecutable(this->Moc, "moc", false)) {
+ return false;
+ }
+ // Let the _autogen target depend on the moc executable
+ if (this->Moc.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Moc.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitUic()
@@ -618,83 +577,123 @@ bool cmQtAutoGenInitializer::InitUic()
}
// Uic executable
- return GetUicExecutable();
+ {
+ if (!this->GetQtExecutable(this->Uic, "uic", true)) {
+ return false;
+ }
+ // Let the _autogen target depend on the uic executable
+ if (this->Uic.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Uic.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitRcc()
{
- return GetRccExecutable();
+ // Rcc executable
+ {
+ if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
+ return false;
+ }
+ // Evaluate test output on demand
+ CompilerFeatures& features = *this->Rcc.ExecutableFeatures;
+ if (!features.Evaluated) {
+ // Look for list options
+ if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
+ if (features.HelpOutput.find("--list") != std::string::npos) {
+ features.ListOptions.emplace_back("--list");
+ } else if (features.HelpOutput.find("-list") != std::string::npos) {
+ features.ListOptions.emplace_back("-list");
+ }
+ }
+ // Evaluation finished
+ features.Evaluated = true;
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitScanFiles()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
+ auto const& kw = this->GlobalInitializer->kw();
+
+ auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
+ bool muIt) -> MUFileHandle {
+ MUFileHandle muf = cm::make_unique<MUFile>();
+ muf->RealPath = cmSystemTools::GetRealPath(fullPath);
+ muf->SF = sf;
+ muf->Generated = sf->GetIsGenerated();
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ muf->SkipMoc = this->Moc.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
+ muf->SkipUic = this->Uic.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (muIt) {
+ muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
+ muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
+ }
+ return muf;
+ };
- // String constants
- std::string const SKIP_AUTOGEN_str = "SKIP_AUTOGEN";
- std::string const SKIP_AUTOMOC_str = "SKIP_AUTOMOC";
- std::string const SKIP_AUTOUIC_str = "SKIP_AUTOUIC";
+ auto addMUFile = [&](MUFileHandle&& muf, bool isHeader) {
+ if ((muf->MocIt || muf->UicIt) && muf->Generated) {
+ this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+ }
+ if (isHeader) {
+ this->AutogenTarget.Headers.emplace(muf->SF, std::move(muf));
+ } else {
+ this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
+ }
+ };
// Scan through target files
{
- // String constants
- std::string const qrc_str = "qrc";
- std::string const SKIP_AUTORCC_str = "SKIP_AUTORCC";
- std::string const AUTORCC_OPTIONS_str = "AUTORCC_OPTIONS";
-
// Scan through target files
std::vector<cmSourceFile*> srcFiles;
this->Target->GetConfigCommonSourceFiles(srcFiles);
for (cmSourceFile* sf : srcFiles) {
- if (sf->GetPropertyAsBool(SKIP_AUTOGEN_str)) {
+ // sf->GetExtension() is only valid after sf->GetFullPath() ...
+ // 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->GetFullPath(&pathError);
+ if (!pathError.empty() || fullPath.empty()) {
continue;
}
-
- // sf->GetExtension() is only valid after sf->GetFullPath() ...
- std::string const& fPath = sf->GetFullPath();
std::string const& ext = sf->GetExtension();
- // Register generated files that will be scanned by moc or uic
- if (this->Moc.Enabled || this->Uic.Enabled) {
- cmSystemTools::FileFormat const fileType =
- cmSystemTools::GetFileFormat(ext);
- if ((fileType == cmSystemTools::CXX_FILE_FORMAT) ||
- (fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
- std::string const absPath = cmSystemTools::GetRealPath(fPath);
- if ((this->Moc.Enabled &&
- !sf->GetPropertyAsBool(SKIP_AUTOMOC_str)) ||
- (this->Uic.Enabled &&
- !sf->GetPropertyAsBool(SKIP_AUTOUIC_str))) {
- // Register source
- const bool generated = sf->GetIsGenerated();
- if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
- if (generated) {
- this->AutogenTarget.HeadersGenerated.push_back(absPath);
- } else {
- this->AutogenTarget.Headers.push_back(absPath);
- }
- } else {
- if (generated) {
- this->AutogenTarget.SourcesGenerated.push_back(absPath);
- } else {
- this->AutogenTarget.Sources.push_back(absPath);
- }
- }
- }
+ // Register files that will be scanned by moc or uic
+ if (this->MocOrUicEnabled()) {
+ switch (cmSystemTools::GetFileFormat(ext)) {
+ case cmSystemTools::HEADER_FILE_FORMAT:
+ addMUFile(makeMUFile(sf, fullPath, true), true);
+ break;
+ case cmSystemTools::CXX_FILE_FORMAT:
+ addMUFile(makeMUFile(sf, fullPath, true), false);
+ break;
+ default:
+ break;
}
}
+
// Register rcc enabled files
if (this->Rcc.Enabled) {
- if ((ext == qrc_str) && !sf->GetPropertyAsBool(SKIP_AUTORCC_str)) {
+ if ((ext == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
+ !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
// Register qrc file
Qrc qrc;
- qrc.QrcFile = cmSystemTools::GetRealPath(fPath);
+ qrc.QrcFile = cmSystemTools::GetRealPath(fullPath);
qrc.QrcName =
cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
qrc.Generated = sf->GetIsGenerated();
// RCC options
{
- std::string const opts = sf->GetSafeProperty(AUTORCC_OPTIONS_str);
+ std::string const opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS);
if (!opts.empty()) {
cmSystemTools::ExpandListArgument(opts, qrc.Options);
}
@@ -710,15 +709,72 @@ bool cmQtAutoGenInitializer::InitScanFiles()
// mocs_compilation.cpp source acknowledged by this target.
this->Target->ClearSourcesCache();
+ // For source files find additional headers and private headers
+ if (this->MocOrUicEnabled()) {
+ std::vector<MUFileHandle> extraHeaders;
+ extraHeaders.reserve(this->AutogenTarget.Sources.size() * 2);
+ // Header search suffixes and extensions
+ std::array<std::string, 2> const suffixes{ { "", "_p" } };
+ auto const& exts = makefile->GetCMakeInstance()->GetHeaderExtensions();
+ // Scan through sources
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ MUFile const& muf = *pair.second;
+ if (muf.MocIt || muf.UicIt) {
+ // Search for the default header file and a private header
+ std::string const& srcPath = muf.SF->GetFullPath();
+ std::string basePath = cmQtAutoGen::SubDirPrefix(srcPath);
+ basePath += cmSystemTools::GetFilenameWithoutLastExtension(srcPath);
+ for (auto const& suffix : suffixes) {
+ std::string const suffixedPath = basePath + suffix;
+ for (auto const& ext : exts) {
+ std::string fullPath = suffixedPath;
+ fullPath += '.';
+ fullPath += ext;
+
+ auto constexpr locationKind = cmSourceFileLocationKind::Known;
+ cmSourceFile* sf = makefile->GetSource(fullPath, locationKind);
+ if (sf != nullptr) {
+ // Check if we know about this header already
+ if (this->AutogenTarget.Headers.find(sf) !=
+ this->AutogenTarget.Headers.end()) {
+ continue;
+ }
+ // We only accept not-GENERATED files that do exist.
+ if (!sf->GetIsGenerated() &&
+ !cmSystemTools::FileExists(fullPath)) {
+ continue;
+ }
+ } else if (cmSystemTools::FileExists(fullPath)) {
+ // Create a new source file for the existing file
+ sf = makefile->CreateSource(fullPath, false, locationKind);
+ }
+
+ if (sf != nullptr) {
+ auto eMuf = makeMUFile(sf, fullPath, true);
+ // Ony process moc/uic when the parent is processed as well
+ if (!muf.MocIt) {
+ eMuf->MocIt = false;
+ }
+ if (!muf.UicIt) {
+ eMuf->UicIt = false;
+ }
+ extraHeaders.emplace_back(std::move(eMuf));
+ }
+ }
+ }
+ }
+ }
+ // Move generated files to main headers list
+ for (auto& eMuf : extraHeaders) {
+ addMUFile(std::move(eMuf), true);
+ }
+ }
+
// Scan through all source files in the makefile to extract moc and uic
// parameters. Historically we support non target source file parameters.
// The reason is that their file names might be discovered from source files
// at generation time.
- if (this->Moc.Enabled || this->Uic.Enabled) {
- // String constants
- std::string const ui_str = "ui";
- std::string const AUTOUIC_OPTIONS_str = "AUTOUIC_OPTIONS";
-
+ if (this->MocOrUicEnabled()) {
for (cmSourceFile* sf : makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->GetFullPath() ...
// Since we're iterating over source files that might be not in the
@@ -728,139 +784,94 @@ bool cmQtAutoGenInitializer::InitScanFiles()
if (!pathError.empty() || fullPath.empty()) {
continue;
}
+ std::string const& ext = sf->GetExtension();
- // Check file type
- auto const fileType = cmSystemTools::GetFileFormat(sf->GetExtension());
- bool const isSource = (fileType == cmSystemTools::CXX_FILE_FORMAT) ||
- (fileType == cmSystemTools::HEADER_FILE_FORMAT);
- bool const isUi = (this->Moc.Enabled && sf->GetExtension() == ui_str);
-
- // Process only certain file types
- if (isSource || isUi) {
- std::string const absFile = cmSystemTools::GetRealPath(fullPath);
- // Acquire file properties
- bool const skipAUTOGEN = sf->GetPropertyAsBool(SKIP_AUTOGEN_str);
- bool const skipMoc = (this->Moc.Enabled && isSource) &&
- (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOMOC_str));
- bool const skipUic = this->Uic.Enabled &&
- (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOUIC_str));
-
- // Register moc and uic skipped file
- if (skipMoc) {
- this->Moc.Skip.insert(absFile);
+ auto const fileFormat = cmSystemTools::GetFileFormat(ext);
+ if (fileFormat == cmSystemTools::HEADER_FILE_FORMAT) {
+ if (this->AutogenTarget.Headers.find(sf) ==
+ this->AutogenTarget.Headers.end()) {
+ auto muf = makeMUFile(sf, fullPath, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+ }
}
- if (skipUic) {
- this->Uic.Skip.insert(absFile);
+ } else if (fileFormat == cmSystemTools::CXX_FILE_FORMAT) {
+ if (this->AutogenTarget.Sources.find(sf) ==
+ this->AutogenTarget.Sources.end()) {
+ auto muf = makeMUFile(sf, fullPath, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ this->AutogenTarget.Sources.emplace(sf, std::move(muf));
+ }
}
-
- // Check if the .ui file has uic options
- if (isUi && !skipUic) {
- std::string const uicOpts = sf->GetSafeProperty(AUTOUIC_OPTIONS_str);
+ } else if (this->Uic.Enabled && (ext == kw.ui)) {
+ // .ui file
+ std::string realPath = cmSystemTools::GetRealPath(fullPath);
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ bool const skipUic =
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (!skipUic) {
+ // Check if the .ui file has uic options
+ std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
if (!uicOpts.empty()) {
- this->Uic.FileFiles.push_back(absFile);
+ this->Uic.FileFiles.push_back(std::move(realPath));
std::vector<std::string> optsVec;
cmSystemTools::ExpandListArgument(uicOpts, optsVec);
this->Uic.FileOptions.push_back(std::move(optsVec));
}
+ } else {
+ // Register skipped .ui file
+ this->Uic.SkipUi.insert(std::move(realPath));
}
}
}
}
// Process GENERATED sources and headers
- if (this->Moc.Enabled || this->Uic.Enabled) {
- if (!this->AutogenTarget.SourcesGenerated.empty() ||
- !this->AutogenTarget.HeadersGenerated.empty()) {
- // Check status of policy CMP0071
- bool policyAccept = false;
- bool policyWarn = false;
- cmPolicies::PolicyStatus const CMP0071_status =
- makefile->GetPolicyStatus(cmPolicies::CMP0071);
- switch (CMP0071_status) {
- case cmPolicies::WARN:
- policyWarn = true;
- CM_FALLTHROUGH;
- case cmPolicies::OLD:
- // Ignore GENERATED file
- break;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::NEW:
- // Process GENERATED file
- policyAccept = true;
- break;
+ if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
+ if (this->CMP0071Accept) {
+ // Let the autogen target depend on the GENERATED files
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ this->AutogenTarget.DependFiles.insert(muf->RealPath);
}
-
- if (policyAccept) {
- // Accept GENERATED sources
- for (std::string const& absFile :
- this->AutogenTarget.HeadersGenerated) {
- this->AutogenTarget.Headers.push_back(absFile);
- this->AutogenTarget.DependFiles.insert(absFile);
- }
- for (std::string const& absFile :
- this->AutogenTarget.SourcesGenerated) {
- this->AutogenTarget.Sources.push_back(absFile);
- this->AutogenTarget.DependFiles.insert(absFile);
- }
- } else {
- if (policyWarn) {
- std::string msg;
- msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
- msg += "\n";
- std::string tools;
- std::string property;
- if (this->Moc.Enabled && this->Uic.Enabled) {
- tools = "AUTOMOC and AUTOUIC";
- property = "SKIP_AUTOGEN";
- } else if (this->Moc.Enabled) {
- tools = "AUTOMOC";
- property = "SKIP_AUTOMOC";
- } else if (this->Uic.Enabled) {
- tools = "AUTOUIC";
- property = "SKIP_AUTOUIC";
- }
- msg += "For compatibility, CMake is excluding the GENERATED source "
- "file(s):\n";
- for (const std::string& absFile :
- this->AutogenTarget.HeadersGenerated) {
- msg.append(" ").append(Quoted(absFile)).append("\n");
- }
- for (const std::string& absFile :
- this->AutogenTarget.SourcesGenerated) {
- msg.append(" ").append(Quoted(absFile)).append("\n");
- }
- msg += "from processing by ";
- msg += tools;
- msg +=
- ". If any of the files should be processed, set CMP0071 to NEW. "
- "If any of the files should not be processed, "
- "explicitly exclude them by setting the source file property ";
- msg += property;
- msg += ":\n set_property(SOURCE file.h PROPERTY ";
- msg += property;
- msg += " ON)\n";
- makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
- }
+ } else if (this->CMP0071Warn) {
+ std::string msg;
+ msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
+ msg += '\n';
+ std::string property;
+ if (this->Moc.Enabled && this->Uic.Enabled) {
+ property = kw.SKIP_AUTOGEN;
+ } else if (this->Moc.Enabled) {
+ property = kw.SKIP_AUTOMOC;
+ } else if (this->Uic.Enabled) {
+ property = kw.SKIP_AUTOUIC;
+ }
+ msg += "For compatibility, CMake is excluding the GENERATED source "
+ "file(s):\n";
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ msg += " ";
+ msg += Quoted(muf->RealPath);
+ msg += '\n';
}
+ msg += "from processing by ";
+ msg += cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false);
+ msg += ". If any of the files should be processed, set CMP0071 to NEW. "
+ "If any of the files should not be processed, "
+ "explicitly exclude them by setting the source file property ";
+ msg += property;
+ msg += ":\n set_property(SOURCE file.h PROPERTY ";
+ msg += property;
+ msg += " ON)\n";
+ makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
}
}
- // Sort headers and sources
- if (this->Moc.Enabled || this->Uic.Enabled) {
- std::sort(this->AutogenTarget.Headers.begin(),
- this->AutogenTarget.Headers.end());
- std::sort(this->AutogenTarget.Sources.begin(),
- this->AutogenTarget.Sources.end());
- }
-
// Process qrc files
if (!this->Rcc.Qrcs.empty()) {
const bool modernQt = (this->QtVersion.Major >= 5);
// Target rcc options
std::vector<std::string> optionsTarget;
cmSystemTools::ExpandListArgument(
- this->Target->GetSafeProperty("AUTORCC_OPTIONS"), optionsTarget);
+ this->Target->GetSafeProperty(kw.AUTORCC_OPTIONS), optionsTarget);
// Check if file name is unique
for (Qrc& qrc : this->Rcc.Qrcs) {
@@ -938,7 +949,9 @@ bool cmQtAutoGenInitializer::InitScanFiles()
for (Qrc& qrc : this->Rcc.Qrcs) {
if (!qrc.Generated) {
std::string error;
- if (!RccListInputs(qrc.QrcFile, qrc.Resources, error)) {
+ RccLister const lister(this->Rcc.Executable,
+ this->Rcc.ExecutableFeatures->ListOptions);
+ if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
cmSystemTools::Error(error);
return false;
}
@@ -961,7 +974,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
// Files provided by the autogen target
std::vector<std::string> autogenProvides;
if (this->Moc.Enabled) {
- this->AddGeneratedSource(this->Moc.MocsCompilation, GeneratorT::MOC, true);
+ this->AddGeneratedSource(this->Moc.MocsCompilation, this->Moc, true);
autogenProvides.push_back(this->Moc.MocsCompilation);
}
@@ -1109,13 +1122,12 @@ bool cmQtAutoGenInitializer::InitRccTargets()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
- auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc");
for (Qrc const& qrc : this->Rcc.Qrcs) {
// Register info file as generated by CMake
makefile->AddCMakeOutputFile(qrc.InfoFile);
// Register file at target
- this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC);
+ this->AddGeneratedSource(qrc.RccFile, this->Rcc);
std::vector<std::string> ccOutput;
ccOutput.push_back(qrc.RccFile);
@@ -1174,8 +1186,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
if (!this->TargetsFolder.empty()) {
autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
}
- if (!rccTargetName.empty()) {
- autoRccTarget->AddUtility(rccTargetName, makefile);
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, makefile);
}
}
// Add autogen target to the origin target dependencies
@@ -1195,8 +1207,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
// Add resource file to the custom command dependencies
ccDepends.push_back(fileName);
}
- if (!rccTargetName.empty()) {
- ccDepends.push_back(rccTargetName);
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ ccDepends.push_back(this->Rcc.ExecutableTargetName);
}
makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
/*main_dependency*/ std::string(),
@@ -1222,7 +1234,7 @@ bool cmQtAutoGenInitializer::SetupCustomTargets()
}
// Generate autogen target info file
- if (this->Moc.Enabled || this->Uic.Enabled) {
+ if (this->MocOrUicEnabled()) {
// Write autogen target info files
if (!this->SetupWriteAutogenInfo()) {
return false;
@@ -1262,22 +1274,131 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
ofs.Write("AM_INCLUDE_DIR", this->Dir.Include);
ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude);
- ofs.Write("# Files\n");
- ofs.WriteStrings("AM_SOURCES", this->AutogenTarget.Sources);
- ofs.WriteStrings("AM_HEADERS", this->AutogenTarget.Headers);
- ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
- ofs.WriteConfig("AM_SETTINGS_FILE",
- this->AutogenTarget.ConfigSettingsFile);
+ std::vector<std::string> headers;
+ std::vector<std::string> headersFlags;
+ std::vector<std::string> headersBuildPaths;
+ std::vector<std::string> sources;
+ std::vector<std::string> sourcesFlags;
+ std::set<std::string> moc_skip;
+ std::set<std::string> uic_skip;
+
+ // Filter headers
+ {
+ auto headerCount = this->AutogenTarget.Headers.size();
+ headers.reserve(headerCount);
+ headersFlags.reserve(headerCount);
+
+ std::vector<MUFile const*> sortedHeaders;
+ {
+ sortedHeaders.reserve(headerCount);
+ for (auto const& pair : this->AutogenTarget.Headers) {
+ sortedHeaders.emplace_back(pair.second.get());
+ }
+ std::sort(sortedHeaders.begin(), sortedHeaders.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
+ }
+
+ for (MUFile const* const muf : sortedHeaders) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ headers.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ headersFlags.emplace_back(std::move(flags));
+ }
+ }
+ }
+ // Header build paths
+ {
+ cmFilePathChecksum const fpathCheckSum(makefile);
+ std::unordered_set<std::string> emitted;
+ for (std::string const& hdr : headers) {
+ std::string basePath = fpathCheckSum.getPart(hdr);
+ basePath += "/moc_";
+ basePath += cmSystemTools::GetFilenameWithoutLastExtension(hdr);
+ for (unsigned int ii = 1; ii != 1024; ++ii) {
+ std::string path = basePath;
+ if (ii > 1) {
+ path += '_';
+ path += std::to_string(ii);
+ }
+ path += ".cpp";
+ if (emitted.emplace(path).second) {
+ headersBuildPaths.emplace_back(std::move(path));
+ break;
+ }
+ }
+ }
+ }
+
+ // Filter sources
+ {
+ auto sourcesCount = this->AutogenTarget.Sources.size();
+ sources.reserve(sourcesCount);
+ sourcesFlags.reserve(sourcesCount);
+
+ std::vector<MUFile const*> sorted;
+ sorted.reserve(sourcesCount);
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ sorted.emplace_back(pair.second.get());
+ }
+ std::sort(sorted.begin(), sorted.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
+
+ for (MUFile const* const muf : sorted) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ sources.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ sourcesFlags.emplace_back(std::move(flags));
+ }
+ }
+ }
ofs.Write("# Qt\n");
ofs.WriteUInt("AM_QT_VERSION_MAJOR", this->QtVersion.Major);
ofs.Write("AM_QT_MOC_EXECUTABLE", this->Moc.Executable);
ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable);
+ ofs.Write("# Files\n");
+ ofs.Write("AM_CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
+ ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
+ ofs.WriteConfig("AM_SETTINGS_FILE",
+ this->AutogenTarget.ConfigSettingsFile);
+ ofs.Write("AM_PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
+ ofs.WriteStrings("AM_HEADERS", headers);
+ ofs.WriteStrings("AM_HEADERS_FLAGS", headersFlags);
+ ofs.WriteStrings("AM_HEADERS_BUILD_PATHS", headersBuildPaths);
+ ofs.WriteStrings("AM_SOURCES", sources);
+ ofs.WriteStrings("AM_SOURCES_FLAGS", sourcesFlags);
+
// Write moc settings
if (this->Moc.Enabled) {
ofs.Write("# MOC settings\n");
- ofs.WriteStrings("AM_MOC_SKIP", this->Moc.Skip);
+ ofs.WriteStrings("AM_MOC_SKIP", moc_skip);
ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines);
ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines);
ofs.WriteStrings("AM_MOC_INCLUDES", this->Moc.Includes);
@@ -1294,8 +1415,11 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
// Write uic settings
if (this->Uic.Enabled) {
+ // Add skipped .ui files
+ uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
+
ofs.Write("# UIC settings\n");
- ofs.WriteStrings("AM_UIC_SKIP", this->Uic.Skip);
+ ofs.WriteStrings("AM_UIC_SKIP", uic_skip);
ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options);
ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions);
ofs.WriteStrings("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles);
@@ -1332,7 +1456,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
ofs.Write("# Rcc executable\n");
ofs.Write("ARCC_RCC_EXECUTABLE", this->Rcc.Executable);
- ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS", this->Rcc.ListOptions);
+ ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS",
+ this->Rcc.ExecutableFeatures->ListOptions);
ofs.Write("# Rcc job\n");
ofs.Write("ARCC_LOCK_FILE", qrc.LockFile);
@@ -1353,23 +1478,74 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
return true;
}
-void cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
- GeneratorT genType,
+void cmQtAutoGenInitializer::RegisterGeneratedSource(
+ std::string const& filename)
+{
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
+ cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
+ gFile->SetProperty("GENERATED", "1");
+ gFile->SetProperty("SKIP_AUTOGEN", "1");
+}
+
+bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
+ GenVarsT const& genVars,
bool prepend)
{
- // Register source file in makefile
+ // Register source at makefile
+ this->RegisterGeneratedSource(filename);
+ // Add source file to target
+ this->Target->AddSource(filename, prepend);
+ // Add source file to source group
+ return this->AddToSourceGroup(filename, genVars.GenNameUpper);
+}
+
+bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
+ std::string const& genNameUpper)
+{
cmMakefile* makefile = this->Target->Target->GetMakefile();
+ cmSourceGroup* sourceGroup = nullptr;
+ // Acquire source group
{
- cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
- gFile->SetProperty("GENERATED", "1");
- gFile->SetProperty("SKIP_AUTOGEN", "On");
+ std::string property;
+ std::string groupName;
+ {
+ // Prefer generator specific source group name
+ std::array<std::string, 2> props{ { genNameUpper + "_SOURCE_GROUP",
+ "AUTOGEN_SOURCE_GROUP" } };
+ for (std::string& prop : props) {
+ const char* propName = makefile->GetState()->GetGlobalProperty(prop);
+ if ((propName != nullptr) && (*propName != '\0')) {
+ groupName = propName;
+ property = std::move(prop);
+ break;
+ }
+ }
+ }
+ // Generate a source group on demand
+ if (!groupName.empty()) {
+ sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
+ if (sourceGroup == nullptr) {
+ std::string err;
+ err += genNameUpper;
+ err += " error in ";
+ err += property;
+ err += ": Could not find or create the source group ";
+ err += cmQtAutoGen::Quoted(groupName);
+ cmSystemTools::Error(err);
+ return false;
+ }
+ }
}
+ if (sourceGroup != nullptr) {
+ sourceGroup->AddGroupFile(fileName);
+ }
+ return true;
+}
- // Add source file to source group
- AddToSourceGroup(makefile, filename, genType);
-
- // Add source file to target
- this->Target->AddSource(filename, prepend);
+void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
+{
+ Target->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName.c_str(),
+ false);
}
static unsigned int CharPtrToUInt(const char* const input)
@@ -1384,8 +1560,12 @@ static unsigned int CharPtrToUInt(const char* const input)
static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions(
cmGeneratorTarget const* target)
{
- cmMakefile* makefile = target->Target->GetMakefile();
+ // Qt version variable prefixes
+ static std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core",
+ "QT" } };
+
std::vector<cmQtAutoGen::IntegerVersion> result;
+ result.reserve(prefixes.size() * 2);
// Adds a version to the result (nullptr safe)
auto addVersion = [&result](const char* major, const char* minor) {
cmQtAutoGen::IntegerVersion ver(CharPtrToUInt(major),
@@ -1394,8 +1574,7 @@ static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions(
result.emplace_back(ver);
}
};
- // Qt version variable prefixes
- std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core", "QT" } };
+ cmMakefile* makefile = target->Target->GetMakefile();
// Read versions from variables
for (const std::string& prefix : prefixes) {
@@ -1439,181 +1618,95 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
return res;
}
-std::pair<bool, std::string> cmQtAutoGenInitializer::GetQtExecutable(
- const std::string& executable, bool ignoreMissingTarget, std::string* output)
+bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
+ const std::string& executable,
+ bool ignoreMissingTarget) const
{
- const std::string upperExecutable = cmSystemTools::UpperCase(executable);
- std::string result = this->Target->Target->GetSafeProperty(
- "AUTO" + upperExecutable + "_EXECUTABLE");
- if (!result.empty()) {
- cmListFileBacktrace lfbt =
- this->Target->Target->GetMakefile()->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(result);
- result = cge->Evaluate(this->Target->GetLocalGenerator(), "");
-
- return std::make_pair(true, result);
- }
-
- std::string err;
-
- // Find executable
- {
- const std::string targetName =
- GetQtExecutableTargetName(this->QtVersion, executable);
- if (targetName.empty()) {
- err = "The AUTO" + upperExecutable + " feature ";
- err += "supports only Qt 4, Qt 5 and Qt 6.";
- } else {
- cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
- cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
- if (tgt != nullptr) {
- if (tgt->IsImported()) {
- result = tgt->ImportedGetLocation("");
- } else {
- result = tgt->GetLocation("");
- }
- } else {
- if (ignoreMissingTarget) {
- return std::make_pair(true, "");
- }
-
- err = "Could not find target " + targetName;
- }
- }
- }
-
- // Test executable
- if (err.empty()) {
- this->GlobalInitializer->GetExecutableTestOutput(executable, result, err,
- output);
- }
-
- // Print error
- if (!err.empty()) {
- std::string msg = "AutoGen (";
+ auto print_err = [this, &genVars](std::string const& err) {
+ std::string msg = genVars.GenNameUpper;
+ msg += " for target ";
msg += this->Target->GetName();
- msg += "): ";
+ msg += ": ";
msg += err;
cmSystemTools::Error(msg);
- return std::make_pair(false, "");
- }
-
- return std::make_pair(true, result);
-}
-
-bool cmQtAutoGenInitializer::GetMocExecutable()
-{
- const auto result = this->GetQtExecutable("moc", false, nullptr);
- this->Moc.Executable = result.second;
- return result.first;
-}
-
-bool cmQtAutoGenInitializer::GetUicExecutable()
-{
- const auto result = this->GetQtExecutable("uic", true, nullptr);
- this->Uic.Executable = result.second;
- return result.first;
-}
+ };
-bool cmQtAutoGenInitializer::GetRccExecutable()
-{
- std::string stdOut;
- const auto result = this->GetQtExecutable("rcc", false, &stdOut);
- this->Rcc.Executable = result.second;
- if (!result.first) {
- return false;
- }
+ // Custom executable
+ {
+ std::string const prop = genVars.GenNameUpper + "_EXECUTABLE";
+ std::string const val = this->Target->Target->GetSafeProperty(prop);
+ if (!val.empty()) {
+ // Evaluate generator expression
+ {
+ cmListFileBacktrace lfbt =
+ this->Target->Target->GetMakefile()->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
+ genVars.Executable =
+ cge->Evaluate(this->Target->GetLocalGenerator(), "");
+ }
+ if (genVars.Executable.empty() && !ignoreMissingTarget) {
+ print_err(prop + " evaluates to an empty value");
+ return false;
+ }
- if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
- if (stdOut.find("--list") != std::string::npos) {
- this->Rcc.ListOptions.emplace_back("--list");
- } else {
- this->Rcc.ListOptions.emplace_back("-list");
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
}
}
- return true;
-}
-/// @brief Reads the resource files list from from a .qrc file
-/// @arg fileName Must be the absolute path of the .qrc file
-/// @return True if the rcc file was successfully read
-bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName,
- std::vector<std::string>& files,
- std::string& error)
-{
- if (!cmSystemTools::FileExists(fileName)) {
- error = "rcc resource file does not exist:\n ";
- error += Quoted(fileName);
- error += "\n";
- return false;
- }
- if (!this->Rcc.ListOptions.empty()) {
- // Use rcc for file listing
- if (this->Rcc.Executable.empty()) {
- error = "rcc executable not available";
- return false;
+ // Find executable target
+ {
+ // Find executable target name
+ std::string targetName;
+ if (this->QtVersion.Major == 4) {
+ targetName = "Qt4::";
+ } else if (this->QtVersion.Major == 5) {
+ targetName = "Qt5::";
+ } else if (this->QtVersion.Major == 6) {
+ targetName = "Qt6::";
}
-
- // Run rcc list command in the directory of the qrc file with the
- // pathless
- // qrc file name argument. This way rcc prints relative paths.
- // This avoids issues on Windows when the qrc file is in a path that
- // contains non-ASCII characters.
- std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
- std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
-
- bool result = false;
- int retVal = 0;
- std::string rccStdOut;
- std::string rccStdErr;
- {
- std::vector<std::string> cmd;
- cmd.push_back(this->Rcc.Executable);
- cmd.insert(cmd.end(), this->Rcc.ListOptions.begin(),
- this->Rcc.ListOptions.end());
- cmd.push_back(fileNameName);
- result = cmSystemTools::RunSingleCommand(
- cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
- cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
- }
- if (!result || retVal) {
- error = "rcc list process failed for:\n ";
- error += Quoted(fileName);
- error += "\n";
- error += rccStdOut;
- error += "\n";
- error += rccStdErr;
- error += "\n";
+ targetName += executable;
+
+ // Find target
+ cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+ cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(targetName);
+ if (target != nullptr) {
+ genVars.ExecutableTargetName = targetName;
+ genVars.ExecutableTarget = target;
+ if (target->IsImported()) {
+ genVars.Executable = target->ImportedGetLocation("");
+ } else {
+ genVars.Executable = target->GetLocation("");
+ }
+ } else {
+ if (ignoreMissingTarget) {
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
+ }
+ std::string err = "Could not find ";
+ err += executable;
+ err += " executable target ";
+ err += targetName;
+ print_err(err);
return false;
}
- if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ }
+
+ // Get executable features
+ {
+ std::string err;
+ genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
+ executable, genVars.Executable, err);
+ if (!genVars.ExecutableFeatures) {
+ print_err(err);
return false;
}
- } else {
- // We can't use rcc for the file listing.
- // Read the qrc file content into string and parse it.
- {
- std::string qrcContents;
- {
- cmsys::ifstream ifs(fileName.c_str());
- if (ifs) {
- std::ostringstream osst;
- osst << ifs.rdbuf();
- qrcContents = osst.str();
- } else {
- error = "rcc file not readable:\n ";
- error += Quoted(fileName);
- error += "\n";
- return false;
- }
- }
- // Parse string content
- RccListParseContent(qrcContents, files);
- }
}
- // Convert relative paths to absolute paths
- RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files);
return true;
}
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index 781dd15d6..aa073d1fd 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -8,15 +8,18 @@
#include "cmQtAutoGen.h"
#include <map>
+#include <memory> // IWYU pragma: keep
#include <ostream>
#include <set>
#include <string>
+#include <unordered_map>
#include <utility>
#include <vector>
class cmGeneratorTarget;
class cmTarget;
class cmQtAutoGenGlobalInitializer;
+class cmSourceFile;
/// @brief Initializes the QtAutoGen generators
class cmQtAutoGenInitializer : public cmQtAutoGen
@@ -40,6 +43,38 @@ public:
std::vector<std::string> Resources;
};
+ /// @brief Moc/Uic file
+ struct MUFile
+ {
+ std::string RealPath;
+ cmSourceFile* SF = nullptr;
+ bool Generated = false;
+ bool SkipMoc = false;
+ bool SkipUic = false;
+ bool MocIt = false;
+ bool UicIt = false;
+ };
+ typedef std::unique_ptr<MUFile> MUFileHandle;
+
+ /// @brief Abstract moc/uic/rcc generator variables base class
+ struct GenVarsT
+ {
+ bool Enabled = false;
+ // Generator type/name
+ GenT Gen;
+ std::string const& GenNameUpper;
+ // Executable
+ std::string ExecutableTargetName;
+ cmGeneratorTarget* ExecutableTarget = nullptr;
+ std::string Executable;
+ CompilerFeaturesHandle ExecutableFeatures;
+
+ /// @brief Constructor
+ GenVarsT(GenT gen)
+ : Gen(gen)
+ , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
+ };
+
/// @brief Writes a CMake info file
class InfoWriter
{
@@ -88,6 +123,12 @@ public:
bool SetupCustomTargets();
private:
+ /// @brief If moc or uic is enabled, the autogen target will be generated
+ bool MocOrUicEnabled() const
+ {
+ return (this->Moc.Enabled || this->Uic.Enabled);
+ }
+
bool InitMoc();
bool InitUic();
bool InitRcc();
@@ -99,20 +140,15 @@ private:
bool SetupWriteAutogenInfo();
bool SetupWriteRccInfo();
- void AddGeneratedSource(std::string const& filename, GeneratorT genType,
+ void RegisterGeneratedSource(std::string const& filename);
+ bool AddGeneratedSource(std::string const& filename, GenVarsT const& genVars,
bool prepend = false);
+ bool AddToSourceGroup(std::string const& fileName,
+ std::string const& genNameUpper);
+ void AddCleanFile(std::string const& fileName);
- bool GetMocExecutable();
- bool GetUicExecutable();
- bool GetRccExecutable();
-
- bool RccListInputs(std::string const& fileName,
- std::vector<std::string>& files,
- std::string& errorMessage);
-
- std::pair<bool, std::string> GetQtExecutable(const std::string& executable,
- bool ignoreMissingTarget,
- std::string* output);
+ bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
+ bool ignoreMissingTarget) const;
private:
cmQtAutoGenGlobalInitializer* GlobalInitializer;
@@ -125,6 +161,8 @@ private:
std::vector<std::string> ConfigsList;
std::string Verbosity;
std::string TargetsFolder;
+ bool CMP0071Accept = false;
+ bool CMP0071Warn = false;
/// @brief Common directories
struct
@@ -146,53 +184,57 @@ private:
// Configuration files
std::string InfoFile;
std::string SettingsFile;
+ std::string ParseCacheFile;
std::map<std::string, std::string> ConfigSettingsFile;
// Dependencies
bool DependOrigin = false;
std::set<std::string> DependFiles;
std::set<cmTarget*> DependTargets;
// Sources to process
- std::vector<std::string> Headers;
- std::vector<std::string> Sources;
- std::vector<std::string> HeadersGenerated;
- std::vector<std::string> SourcesGenerated;
+ std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
+ std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
+ std::vector<MUFile*> FilesGenerated;
} AutogenTarget;
/// @brief Moc only variables
- struct
+ struct MocT : public GenVarsT
{
- bool Enabled = false;
- std::string Executable;
std::string PredefsCmd;
- std::set<std::string> Skip;
std::vector<std::string> Includes;
std::map<std::string, std::vector<std::string>> ConfigIncludes;
std::set<std::string> Defines;
std::map<std::string, std::set<std::string>> ConfigDefines;
std::string MocsCompilation;
+
+ /// @brief Constructor
+ MocT()
+ : GenVarsT(GenT::MOC){};
} Moc;
- ///@brief Uic only variables
- struct
+ /// @brief Uic only variables
+ struct UicT : public GenVarsT
{
- bool Enabled = false;
- std::string Executable;
- std::set<std::string> Skip;
+ std::set<std::string> SkipUi;
std::vector<std::string> SearchPaths;
std::vector<std::string> Options;
std::map<std::string, std::vector<std::string>> ConfigOptions;
std::vector<std::string> FileFiles;
std::vector<std::vector<std::string>> FileOptions;
+
+ /// @brief Constructor
+ UicT()
+ : GenVarsT(GenT::UIC){};
} Uic;
/// @brief Rcc only variables
- struct
+ struct RccT : public GenVarsT
{
- bool Enabled = false;
bool GlobalTarget = false;
- std::string Executable;
- std::vector<std::string> ListOptions;
std::vector<Qrc> Qrcs;
+
+ /// @brief Constructor
+ RccT()
+ : GenVarsT(GenT::RCC){};
} Rcc;
};
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index e2d7debed..e1c435be0 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -14,10 +14,33 @@
#include "cmSystemTools.h"
#include "cmake.h"
-#include <algorithm>
-#include <utility>
+cmQtAutoGenerator::Logger::Logger()
+{
+ // Initialize logger
+ {
+ std::string verbose;
+ if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
+ unsigned long iVerbose = 0;
+ if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
+ SetVerbosity(static_cast<unsigned int>(iVerbose));
+ } else {
+ // Non numeric verbosity
+ SetVerbose(cmSystemTools::IsOn(verbose));
+ }
+ }
+ }
+ {
+ std::string colorEnv;
+ cmSystemTools::GetEnv("COLOR", colorEnv);
+ if (!colorEnv.empty()) {
+ SetColorOutput(cmSystemTools::IsOn(colorEnv));
+ } else {
+ SetColorOutput(true);
+ }
+ }
+}
-// -- Class methods
+cmQtAutoGenerator::Logger::~Logger() = default;
void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
{
@@ -43,8 +66,8 @@ std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title)
return head;
}
-void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Info(GenT genType,
+ std::string const& message) const
{
std::string msg = GeneratorName(genType);
msg += ": ";
@@ -58,8 +81,8 @@ void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Warning(GenT genType,
+ std::string const& message) const
{
std::string msg;
if (message.find('\n') == std::string::npos) {
@@ -82,9 +105,9 @@ void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
std::string const& filename,
- std::string const& message)
+ std::string const& message) const
{
std::string msg = " ";
msg += Quoted(filename);
@@ -94,8 +117,8 @@ void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
Warning(genType, msg);
}
-void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Error(GenT genType,
+ std::string const& message) const
{
std::string msg;
msg += HeadLine(GeneratorName(genType) + " error");
@@ -111,9 +134,9 @@ void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
std::string const& filename,
- std::string const& message)
+ std::string const& message) const
{
std::string emsg = " ";
emsg += Quoted(filename);
@@ -124,8 +147,8 @@ void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
}
void cmQtAutoGenerator::Logger::ErrorCommand(
- GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output)
+ GenT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output) const
{
std::string msg;
msg.push_back('\n');
@@ -153,528 +176,101 @@ void cmQtAutoGenerator::Logger::ErrorCommand(
}
}
-std::string cmQtAutoGenerator::FileSystem::GetRealPath(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::GetRealPath(filename);
-}
-
-std::string cmQtAutoGenerator::FileSystem::CollapseCombinedPath(
- std::string const& dir, std::string const& file)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::CollapseCombinedPath(dir, file);
-}
-
-void cmQtAutoGenerator::FileSystem::SplitPath(
- const std::string& p, std::vector<std::string>& components,
- bool expand_home_dir)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- cmSystemTools::SplitPath(p, components, expand_home_dir);
-}
-
-std::string cmQtAutoGenerator::FileSystem::JoinPath(
- const std::vector<std::string>& components)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::JoinPath(components);
-}
-
-std::string cmQtAutoGenerator::FileSystem::JoinPath(
- std::vector<std::string>::const_iterator first,
- std::vector<std::string>::const_iterator last)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::JoinPath(first, last);
-}
-
-std::string cmQtAutoGenerator::FileSystem::GetFilenameWithoutLastExtension(
- const std::string& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::GetFilenameWithoutLastExtension(filename);
-}
-
-std::string cmQtAutoGenerator::FileSystem::SubDirPrefix(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmQtAutoGen::SubDirPrefix(filename);
-}
-
-void cmQtAutoGenerator::FileSystem::setupFilePathChecksum(
- std::string const& currentSrcDir, std::string const& currentBinDir,
- std::string const& projectSrcDir, std::string const& projectBinDir)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- FilePathChecksum_.setupParentDirs(currentSrcDir, currentBinDir,
- projectSrcDir, projectBinDir);
-}
-
-std::string cmQtAutoGenerator::FileSystem::GetFilePathChecksum(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return FilePathChecksum_.getPart(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileExists(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename,
- bool isFile)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileExists(filename, isFile);
-}
-
-unsigned long cmQtAutoGenerator::FileSystem::FileLength(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileLength(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileIsOlderThan(
- std::string const& buildFile, std::string const& sourceFile,
- std::string* error)
-{
- bool res(false);
- int result = 0;
- {
- std::lock_guard<std::mutex> lock(Mutex_);
- res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result);
- }
- if (res) {
- res = (result < 0);
- } else {
- if (error != nullptr) {
- error->append(
- "File modification time comparison failed for the files\n ");
- error->append(Quoted(buildFile));
- error->append("\nand\n ");
- error->append(Quoted(sourceFile));
- }
- }
- return res;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
- std::string const& filename,
- std::string* error)
-{
- bool success = false;
- if (FileExists(filename, true)) {
- unsigned long const length = FileLength(filename);
- {
- std::lock_guard<std::mutex> lock(Mutex_);
- cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
- if (ifs) {
- content.reserve(length);
- content.assign(std::istreambuf_iterator<char>{ ifs },
- std::istreambuf_iterator<char>{});
- if (ifs) {
- success = true;
- } else {
- content.clear();
- if (error != nullptr) {
- error->append("Reading from the file failed.");
- }
- }
- } else if (error != nullptr) {
- error->append("Opening the file for reading failed.");
- }
- }
- } else if (error != nullptr) {
- error->append(
- "The file does not exist, is not readable or is a directory.");
- }
- return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType,
- std::string& content,
- std::string const& filename)
-{
- std::string error;
- if (!FileRead(content, filename, &error)) {
- Log()->ErrorFile(genType, filename, error);
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
- std::string const& content,
- std::string* error)
-{
- bool success = false;
- // Make sure the parent directory exists
- if (MakeParentDirectory(filename)) {
- std::lock_guard<std::mutex> lock(Mutex_);
- cmsys::ofstream outfile;
- outfile.open(filename.c_str(),
- (std::ios::out | std::ios::binary | std::ios::trunc));
- if (outfile) {
- outfile << content;
- // Check for write errors
- if (outfile.good()) {
- success = true;
- } else {
- if (error != nullptr) {
- error->assign("File writing failed");
- }
- }
- } else {
- if (error != nullptr) {
- error->assign("Opening file for writing failed");
- }
- }
- } else {
- if (error != nullptr) {
- error->assign("Could not create parent directory");
- }
- }
- return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType,
- std::string const& filename,
- std::string const& content)
-{
- std::string error;
- if (!FileWrite(filename, content, &error)) {
- Log()->ErrorFile(genType, filename, error);
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
- std::string const& content)
-{
- bool differs = true;
- {
- std::string oldContents;
- if (FileRead(oldContents, filename)) {
- differs = (oldContents != content);
- }
- }
- return differs;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::RemoveFile(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename,
- bool create)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::Touch(filename, create);
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::MakeDirectory(dirname);
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType,
- std::string const& dirname)
-{
- if (!MakeDirectory(dirname)) {
- Log()->ErrorFile(genType, dirname, "Could not create directory");
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
- std::string const& filename)
+bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
{
bool success = true;
std::string const dirName = cmSystemTools::GetFilenamePath(filename);
if (!dirName.empty()) {
- success = MakeDirectory(dirName);
+ success = cmSystemTools::MakeDirectory(dirName);
}
return success;
}
-bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
- GeneratorT genType, std::string const& filename)
+bool cmQtAutoGenerator::FileRead(std::string& content,
+ std::string const& filename,
+ std::string* error)
{
- if (!MakeParentDirectory(filename)) {
- Log()->ErrorFile(genType, filename, "Could not create parent directory");
+ content.clear();
+ if (!cmSystemTools::FileExists(filename, true)) {
+ if (error != nullptr) {
+ *error = "Not a file.";
+ }
return false;
}
- return true;
-}
-int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop,
- ReadOnlyProcessT* process)
-{
- Process_ = process;
- Target_ = nullptr;
- return UVPipe_.init(*uv_loop, 0, this);
-}
-
-int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target)
-{
- Target_ = target;
- return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData);
-}
+ unsigned long const length = cmSystemTools::FileLength(filename);
+ cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset()
-{
- Process_ = nullptr;
- Target_ = nullptr;
- UVPipe_.reset();
- Buffer_.clear();
- Buffer_.shrink_to_fit();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle,
- size_t suggestedSize,
- uv_buf_t* buf)
-{
- auto& pipe = *reinterpret_cast<PipeT*>(handle->data);
- pipe.Buffer_.resize(suggestedSize);
- buf->base = &pipe.Buffer_.front();
- buf->len = pipe.Buffer_.size();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream,
- ssize_t nread,
- const uv_buf_t* buf)
-{
- auto& pipe = *reinterpret_cast<PipeT*>(stream->data);
- if (nread > 0) {
- // Append data to merged output
- if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) {
- pipe.Target_->append(buf->base, nread);
+ // Use lambda to save destructor calls of ifs
+ return [&ifs, length, &content, error]() -> bool {
+ if (!ifs) {
+ if (error != nullptr) {
+ *error = "Opening the file for reading failed.";
+ }
+ return false;
}
- } else if (nread < 0) {
- // EOF or error
- auto* proc = pipe.Process_;
- // Check it this an unusual error
- if (nread != UV_EOF) {
- if (!proc->Result()->error()) {
- proc->Result()->ErrorMessage =
- "libuv reading from pipe failed with error code ";
- proc->Result()->ErrorMessage += std::to_string(nread);
+ content.reserve(length);
+ typedef std::istreambuf_iterator<char> IsIt;
+ content.assign(IsIt{ ifs }, IsIt{});
+ if (!ifs) {
+ content.clear();
+ if (error != nullptr) {
+ *error = "Reading from the file failed.";
}
+ return false;
}
- // Clear libuv pipe handle and try to finish
- pipe.reset();
- proc->UVTryFinish();
- }
-}
-
-void cmQtAutoGenerator::ProcessResultT::reset()
-{
- ExitStatus = 0;
- TermSignal = 0;
- if (!StdOut.empty()) {
- StdOut.clear();
- StdOut.shrink_to_fit();
- }
- if (!StdErr.empty()) {
- StdErr.clear();
- StdErr.shrink_to_fit();
- }
- if (!ErrorMessage.empty()) {
- ErrorMessage.clear();
- ErrorMessage.shrink_to_fit();
- }
+ return true;
+ }();
}
-void cmQtAutoGenerator::ReadOnlyProcessT::setup(
- ProcessResultT* result, bool mergedOutput,
- std::vector<std::string> const& command, std::string const& workingDirectory)
+bool cmQtAutoGenerator::FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error)
{
- Setup_.WorkingDirectory = workingDirectory;
- Setup_.Command = command;
- Setup_.Result = result;
- Setup_.MergedOutput = mergedOutput;
-}
-
-bool cmQtAutoGenerator::ReadOnlyProcessT::start(
- uv_loop_t* uv_loop, std::function<void()>&& finishedCallback)
-{
- if (IsStarted() || (Result() == nullptr)) {
- return false;
- }
-
- // Reset result before the start
- 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());
- }
- CommandPtr_.push_back(nullptr);
- } else {
- Result()->ErrorMessage = "Empty command";
- }
-
- if (!Result()->error()) {
- if (UVPipeOut_.init(uv_loop, this) != 0) {
- Result()->ErrorMessage = "libuv stdout pipe initialization failed";
- }
- }
- if (!Result()->error()) {
- if (UVPipeErr_.init(uv_loop, this) != 0) {
- Result()->ErrorMessage = "libuv stderr pipe initialization failed";
- }
- }
- if (!Result()->error()) {
- // -- Setup process stdio options
- // stdin
- UVOptionsStdIO_[0].flags = UV_IGNORE;
- UVOptionsStdIO_[0].data.stream = nullptr;
- // stdout
- UVOptionsStdIO_[1].flags =
- static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
- UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
- // stderr
- UVOptionsStdIO_[2].flags =
- static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
- UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
-
- // -- Setup process options
- std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
- UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit;
- UVOptions_.file = CommandPtr_[0];
- UVOptions_.args = const_cast<char**>(&CommandPtr_.front());
- UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
- UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
- UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
- UVOptions_.stdio = &UVOptionsStdIO_.front();
-
- // -- Spawn process
- if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) {
- Result()->ErrorMessage = "libuv process spawn failed";
- }
- }
- // -- Start reading from stdio streams
- if (!Result()->error()) {
- if (UVPipeOut_.startRead(&Result()->StdOut) != 0) {
- Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
- }
- }
- if (!Result()->error()) {
- if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut
- : &Result()->StdErr) != 0) {
- Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
+ // Make sure the parent directory exists
+ if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
+ if (error != nullptr) {
+ *error = "Could not create parent directory.";
}
+ return false;
}
+ cmsys::ofstream ofs;
+ ofs.open(filename.c_str(),
+ (std::ios::out | std::ios::binary | std::ios::trunc));
- if (!Result()->error()) {
- IsStarted_ = true;
- FinishedCallback_ = std::move(finishedCallback);
- } else {
- // Clear libuv handles and finish
- UVProcess_.reset();
- UVPipeOut_.reset();
- UVPipeErr_.reset();
- CommandPtr_.clear();
- }
-
- return IsStarted();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle,
- int64_t exitStatus,
- int termSignal)
-{
- auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data);
- if (proc.IsStarted() && !proc.IsFinished()) {
- // Set error message on demand
- proc.Result()->ExitStatus = exitStatus;
- proc.Result()->TermSignal = termSignal;
- if (!proc.Result()->error()) {
- if (termSignal != 0) {
- proc.Result()->ErrorMessage = "Process was terminated by signal ";
- proc.Result()->ErrorMessage +=
- std::to_string(proc.Result()->TermSignal);
- } else if (exitStatus != 0) {
- proc.Result()->ErrorMessage = "Process failed with return value ";
- proc.Result()->ErrorMessage +=
- std::to_string(proc.Result()->ExitStatus);
+ // Use lambda to save destructor calls of ofs
+ return [&ofs, &content, error]() -> bool {
+ if (!ofs) {
+ if (error != nullptr) {
+ *error = "Opening file for writing failed.";
}
+ return false;
}
-
- // Reset process handle and try to finish
- proc.UVProcess_.reset();
- proc.UVTryFinish();
- }
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::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) {
- if (UVPipeOut_.uv_pipe() == nullptr) {
- if (UVPipeErr_.uv_pipe() == nullptr) {
- IsFinished_ = true;
- FinishedCallback_();
+ ofs << content;
+ if (!ofs.good()) {
+ if (error != nullptr) {
+ *error = "File writing failed.";
}
+ return false;
}
- }
+ return true;
+ }();
}
-cmQtAutoGenerator::cmQtAutoGenerator()
- : FileSys_(&Logger_)
+bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
+ std::string const& content)
{
- // Initialize logger
- {
- std::string verbose;
- if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
- unsigned long iVerbose = 0;
- if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
- Logger_.SetVerbosity(static_cast<unsigned int>(iVerbose));
- } else {
- // Non numeric verbosity
- Logger_.SetVerbose(cmSystemTools::IsOn(verbose));
- }
- }
- }
- {
- std::string colorEnv;
- cmSystemTools::GetEnv("COLOR", colorEnv);
- if (!colorEnv.empty()) {
- Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv));
- } else {
- Logger_.SetColorOutput(true);
- }
+ bool differs = true;
+ std::string oldContents;
+ if (FileRead(oldContents, filename) && (oldContents == content)) {
+ differs = false;
}
-
- // Initialize libuv loop
- uv_disable_stdio_inheritance();
-#ifdef CMAKE_UV_SIGNAL_HACK
- UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
-#endif
- UVLoop_ = cm::make_unique<uv_loop_t>();
- uv_loop_init(UVLoop());
+ return differs;
}
-cmQtAutoGenerator::~cmQtAutoGenerator()
-{
- // Close libuv loop
- uv_loop_close(UVLoop());
-}
+cmQtAutoGenerator::cmQtAutoGenerator() = default;
+
+cmQtAutoGenerator::~cmQtAutoGenerator() = default;
bool cmQtAutoGenerator::Run(std::string const& infoFile,
std::string const& config)
@@ -682,6 +278,13 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
// Info settings
InfoFile_ = infoFile;
cmSystemTools::ConvertToUnixSlashes(InfoFile_);
+ if (!InfoFileTime_.Load(InfoFile_)) {
+ std::string msg = "AutoGen: The info file ";
+ msg += Quoted(InfoFile_);
+ msg += " is not readable\n";
+ cmSystemTools::Stderr(msg);
+ return false;
+ }
InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
InfoConfig_ = config;
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
index 9956a99a3..ff4c4c942 100644
--- a/Source/cmQtAutoGenerator.h
+++ b/Source/cmQtAutoGenerator.h
@@ -5,239 +5,73 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmFilePathChecksum.h"
+#include "cmFileTime.h"
#include "cmQtAutoGen.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
-#include "cm_uv.h"
-#include <array>
-#include <functional>
#include <mutex>
-#include <stddef.h>
-#include <stdint.h>
#include <string>
#include <vector>
class cmMakefile;
-/// @brief Base class for QtAutoGen gernerators
+/** \class cmQtAutoGenerator
+ * \brief Base class for QtAutoGen generators
+ */
class cmQtAutoGenerator : public cmQtAutoGen
{
public:
// -- Types
- /// @brief Thread safe logging
+ /**
+ * Thread safe logger
+ */
class Logger
{
public:
+ // -- Construction
+ Logger();
+ ~Logger();
// -- Verbosity
unsigned int Verbosity() const { return this->Verbosity_; }
void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
void RaiseVerbosity(std::string const& value);
bool Verbose() const { return (this->Verbosity_ != 0); }
void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; }
+ // -- Color output
bool ColorOutput() const { return this->ColorOutput_; }
void SetColorOutput(bool value);
// -- Log info
- void Info(GeneratorT genType, std::string const& message);
+ void Info(GenT genType, std::string const& message) const;
// -- Log warning
- void Warning(GeneratorT genType, std::string const& message);
- void WarningFile(GeneratorT genType, std::string const& filename,
- std::string const& message);
+ void Warning(GenT genType, std::string const& message) const;
+ void WarningFile(GenT genType, std::string const& filename,
+ std::string const& message) const;
// -- Log error
- void Error(GeneratorT genType, std::string const& message);
- void ErrorFile(GeneratorT genType, std::string const& filename,
- std::string const& message);
- void ErrorCommand(GeneratorT genType, std::string const& message,
+ void Error(GenT genType, std::string const& message) const;
+ void ErrorFile(GenT genType, std::string const& filename,
+ std::string const& message) const;
+ void ErrorCommand(GenT genType, std::string const& message,
std::vector<std::string> const& command,
- std::string const& output);
+ std::string const& output) const;
private:
static std::string HeadLine(std::string const& title);
private:
- std::mutex Mutex_;
+ mutable std::mutex Mutex_;
unsigned int Verbosity_ = 0;
bool ColorOutput_ = false;
};
- /// @brief Thread safe file system interface
- class FileSystem
- {
- public:
- FileSystem(Logger* log)
- : Log_(log)
- {
- }
-
- /// @brief Logger
- Logger* Log() const { return Log_; }
-
- // -- Paths
- /// @brief Wrapper for cmSystemTools::GetRealPath
- std::string GetRealPath(std::string const& filename);
- /// @brief Wrapper for cmSystemTools::CollapseCombinedPath
- std::string CollapseCombinedPath(std::string const& dir,
- std::string const& file);
- /// @brief Wrapper for cmSystemTools::SplitPath
- void SplitPath(const std::string& p, std::vector<std::string>& components,
- bool expand_home_dir = true);
- /// @brief Wrapper for cmSystemTools::JoinPath
- std::string JoinPath(const std::vector<std::string>& components);
- /// @brief Wrapper for cmSystemTools::JoinPath
- std::string JoinPath(std::vector<std::string>::const_iterator first,
- std::vector<std::string>::const_iterator last);
- /// @brief Wrapper for cmSystemTools::GetFilenameWithoutLastExtension
- std::string GetFilenameWithoutLastExtension(const std::string& filename);
- /// @brief Wrapper for cmQtAutoGen::SubDirPrefix
- std::string SubDirPrefix(std::string const& filename);
- /// @brief Wrapper for cmFilePathChecksum::setupParentDirs
- void setupFilePathChecksum(std::string const& currentSrcDir,
- std::string const& currentBinDir,
- std::string const& projectSrcDir,
- std::string const& projectBinDir);
- /// @brief Wrapper for cmFilePathChecksum::getPart
- std::string GetFilePathChecksum(std::string const& filename);
-
- // -- File access
- /// @brief Wrapper for cmSystemTools::FileExists
- bool FileExists(std::string const& filename);
- /// @brief Wrapper for cmSystemTools::FileExists
- bool FileExists(std::string const& filename, bool isFile);
- /// @brief Wrapper for cmSystemTools::FileLength
- unsigned long FileLength(std::string const& filename);
- bool FileIsOlderThan(std::string const& buildFile,
- std::string const& sourceFile,
- std::string* error = nullptr);
-
- bool FileRead(std::string& content, std::string const& filename,
- std::string* error = nullptr);
- /// @brief Error logging version
- bool FileRead(GeneratorT genType, std::string& content,
- std::string const& filename);
-
- bool FileWrite(std::string const& filename, std::string const& content,
- std::string* error = nullptr);
- /// @brief Error logging version
- bool FileWrite(GeneratorT genType, std::string const& filename,
- std::string const& content);
-
- bool FileDiffers(std::string const& filename, std::string const& content);
-
- bool FileRemove(std::string const& filename);
- bool Touch(std::string const& filename, bool create = false);
-
- // -- Directory access
- bool MakeDirectory(std::string const& dirname);
- /// @brief Error logging version
- bool MakeDirectory(GeneratorT genType, std::string const& dirname);
-
- bool MakeParentDirectory(std::string const& filename);
- /// @brief Error logging version
- bool MakeParentDirectory(GeneratorT genType, std::string const& filename);
-
- private:
- std::mutex Mutex_;
- cmFilePathChecksum FilePathChecksum_;
- Logger* Log_;
- };
-
- /// @brief Return value and output of an external process
- struct ProcessResultT
- {
- void reset();
- bool error() const
- {
- return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
- }
-
- std::int64_t ExitStatus = 0;
- int TermSignal = 0;
- std::string StdOut;
- std::string StdErr;
- std::string ErrorMessage;
- };
-
- /// @brief External process management class
- struct ReadOnlyProcessT
- {
- // -- Types
-
- /// @brief libuv pipe buffer class
- class PipeT
- {
- public:
- int init(uv_loop_t* uv_loop, ReadOnlyProcessT* process);
- int startRead(std::string* target);
- void reset();
-
- // -- Libuv casts
- uv_pipe_t* uv_pipe() { return UVPipe_.get(); }
- uv_stream_t* uv_stream()
- {
- return reinterpret_cast<uv_stream_t*>(uv_pipe());
- }
- uv_handle_t* uv_handle()
- {
- return reinterpret_cast<uv_handle_t*>(uv_pipe());
- }
-
- // -- Libuv callbacks
- static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
- uv_buf_t* buf);
- static void UVData(uv_stream_t* stream, ssize_t nread,
- const uv_buf_t* buf);
-
- private:
- ReadOnlyProcessT* Process_ = nullptr;
- std::string* Target_ = nullptr;
- std::vector<char> Buffer_;
- cm::uv_pipe_ptr UVPipe_;
- };
-
- /// @brief Process settings
- struct SetupT
- {
- std::string WorkingDirectory;
- std::vector<std::string> Command;
- ProcessResultT* Result = nullptr;
- bool MergedOutput = false;
- };
-
- // -- Const accessors
- const SetupT& Setup() const { return Setup_; }
- ProcessResultT* Result() const { return Setup_.Result; }
- bool IsStarted() const { return IsStarted_; }
- bool IsFinished() const { return IsFinished_; }
-
- // -- Runtime
- void setup(ProcessResultT* result, bool mergedOutput,
- std::vector<std::string> const& command,
- std::string const& workingDirectory = std::string());
- bool start(uv_loop_t* uv_loop, std::function<void()>&& finishedCallback);
-
- private:
- // -- Friends
- friend class PipeT;
- // -- Libuv callbacks
- static void UVExit(uv_process_t* handle, int64_t exitStatus,
- int termSignal);
- void UVTryFinish();
-
- // -- Setup
- SetupT Setup_;
- // -- Runtime
- bool IsStarted_ = false;
- bool IsFinished_ = false;
- std::function<void()> FinishedCallback_;
- std::vector<const char*> CommandPtr_;
- std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
- uv_process_options_t UVOptions_;
- cm::uv_process_ptr UVProcess_;
- PipeT UVPipeOut_;
- PipeT UVPipeErr_;
- };
+ // -- File system methods
+ static bool MakeParentDirectory(std::string const& filename);
+ static bool FileRead(std::string& content, std::string const& filename,
+ std::string* error = nullptr);
+ static bool FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error = nullptr);
+ static bool FileDiffers(std::string const& filename,
+ std::string const& content);
public:
// -- Constructors
@@ -250,18 +84,11 @@ public:
// -- Run
bool Run(std::string const& infoFile, std::string const& config);
- // -- Accessors
- // Logging
- Logger& Log() { return Logger_; }
- // File System
- FileSystem& FileSys() { return FileSys_; }
- // InfoFile
+ // -- InfoFile
std::string const& InfoFile() const { return InfoFile_; }
+ cmFileTime const& InfoFileTime() const { return InfoFileTime_; }
std::string const& InfoDir() const { return InfoDir_; }
std::string const& InfoConfig() const { return InfoConfig_; }
- // libuv loop
- uv_loop_t* UVLoop() { return UVLoop_.get(); }
- cm::uv_async_ptr& UVRequest() { return UVRequest_; }
// -- Utility
static std::string SettingsFind(std::string const& content, const char* key);
@@ -272,19 +99,11 @@ protected:
virtual bool Process() = 0;
private:
- // -- Logging
- Logger Logger_;
- FileSystem FileSys_;
// -- Info settings
std::string InfoFile_;
+ cmFileTime InfoFileTime_;
std::string InfoDir_;
std::string InfoConfig_;
-// -- libuv loop
-#ifdef CMAKE_UV_SIGNAL_HACK
- std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_;
-#endif
- std::unique_ptr<uv_loop_t> UVLoop_;
- cm::uv_async_ptr UVRequest_;
};
#endif
diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx
deleted file mode 100644
index ddff4cf87..000000000
--- a/Source/cmQtAutoGeneratorMocUic.cxx
+++ /dev/null
@@ -1,2042 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmQtAutoGeneratorMocUic.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <functional>
-#include <list>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <utility>
-
-#include "cmAlgorithms.h"
-#include "cmCryptoHash.h"
-#include "cmMakefile.h"
-#include "cmQtAutoGen.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-#if defined(__APPLE__)
-# include <unistd.h>
-#endif
-
-// -- Class methods
-
-std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
- std::string const& relativePath) const
-{
- return FileSys->CollapseCombinedPath(AutogenBuildDir, relativePath);
-}
-
-/**
- * @brief Tries to find the header file to the given file base path by
- * appending different header extensions
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader(
- std::string& header, std::string const& testBasePath) const
-{
- for (std::string const& ext : HeaderExtensions) {
- std::string testFilePath(testBasePath);
- testFilePath.push_back('.');
- testFilePath += ext;
- if (FileSys->FileExists(testFilePath)) {
- header = testFilePath;
- return true;
- }
- }
- return false;
-}
-
-bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped(
- std::string const& fileName) const
-{
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
-}
-
-/**
- * @brief Returns the first relevant Qt macro name found in the given C++ code
- * @return The name of the Qt macro or an empty string
- */
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindMacro(
- std::string const& content) const
-{
- for (KeyExpT const& filter : MacroFilters) {
- // Run a simple find string operation before the expensive
- // regular expression check
- if (content.find(filter.Key) != std::string::npos) {
- cmsys::RegularExpressionMatch match;
- if (filter.Exp.find(content.c_str(), match)) {
- // Return macro name on demand
- return filter.Key;
- }
- }
- }
- return std::string();
-}
-
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const
-{
- std::string res;
- const auto itB = MacroFilters.cbegin();
- const auto itE = MacroFilters.cend();
- const auto itL = itE - 1;
- auto itC = itB;
- for (; itC != itE; ++itC) {
- // Separator
- if (itC != itB) {
- if (itC != itL) {
- res += ", ";
- } else {
- res += " or ";
- }
- }
- // Key
- res += itC->Key;
- }
- return res;
-}
-
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile(
- std::string const& sourcePath, std::string const& includeString) const
-{
- // Search in vicinity of the source
- {
- std::string testPath = sourcePath;
- testPath += includeString;
- if (FileSys->FileExists(testPath)) {
- return FileSys->GetRealPath(testPath);
- }
- }
- // Search in include directories
- for (std::string const& path : IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeString;
- if (FileSys->FileExists(fullPath)) {
- return FileSys->GetRealPath(fullPath);
- }
- }
- // Return empty string
- return std::string();
-}
-
-void cmQtAutoGeneratorMocUic::MocSettingsT::FindDependencies(
- std::string const& content, std::set<std::string>& depends) const
-{
- if (!DependFilters.empty() && !content.empty()) {
- for (KeyExpT const& filter : DependFilters) {
- // Run a simple find string check
- if (content.find(filter.Key) != std::string::npos) {
- // Run the expensive regular expression check loop
- const char* contentChars = content.c_str();
- cmsys::RegularExpressionMatch match;
- while (filter.Exp.find(contentChars, match)) {
- {
- std::string dep = match.match(1);
- if (!dep.empty()) {
- depends.emplace(std::move(dep));
- }
- }
- contentChars += match.end();
- }
- }
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped(
- std::string const& fileName) const
-{
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
-}
-
-void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk)
-{
- if (AutoMoc && Header) {
- // Don't parse header for moc if the file is included by a source already
- if (wrk.Gen().ParallelMocIncluded(FileName)) {
- AutoMoc = false;
- }
- }
-
- if (AutoMoc || AutoUic) {
- std::string error;
- MetaT meta;
- if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) {
- if (!meta.Content.empty()) {
- meta.FileDir = wrk.FileSys().SubDirPrefix(FileName);
- meta.FileBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(FileName);
-
- bool success = true;
- if (AutoMoc) {
- if (Header) {
- success = ParseMocHeader(wrk, meta);
- } else {
- success = ParseMocSource(wrk, meta);
- }
- }
- if (AutoUic && success) {
- ParseUic(wrk, meta);
- }
- } else {
- wrk.LogFileWarning(GeneratorT::GEN, FileName,
- "The source file is empty");
- }
- } else {
- wrk.LogFileError(GeneratorT::GEN, FileName,
- "Could not read the file: " + error);
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk,
- MetaT const& meta)
-{
- struct JobPre
- {
- bool self; // source file is self
- bool underscore; // "moc_" style include
- std::string SourceFile;
- std::string IncludeString;
- };
-
- struct MocInclude
- {
- std::string Inc; // full include string
- std::string Dir; // include string directory
- std::string Base; // include string file base
- };
-
- // Check if this source file contains a relevant macro
- std::string const ownMacro = wrk.Moc().FindMacro(meta.Content);
-
- // Extract moc includes from file
- std::deque<MocInclude> mocIncsUsc;
- std::deque<MocInclude> mocIncsDot;
- {
- if (meta.Content.find("moc") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Moc().RegExpInclude.find(contentChars, match)) {
- std::string incString = match.match(2);
- std::string incDir(wrk.FileSys().SubDirPrefix(incString));
- std::string incBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(incString);
- if (cmHasLiteralPrefix(incBase, "moc_")) {
- // moc_<BASE>.cxx
- // Remove the moc_ part from the base name
- mocIncsUsc.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), incBase.substr(4) });
- } else {
- // <BASE>.moc
- mocIncsDot.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), std::move(incBase) });
- }
- // Forward content pointer
- contentChars += match.end();
- }
- }
- }
-
- // Check if there is anything to do
- if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
- return true;
- }
-
- bool ownDotMocIncluded = false;
- bool ownMocUscIncluded = false;
- std::deque<JobPre> jobs;
-
- // Process moc_<BASE>.cxx includes
- for (const MocInclude& mocInc : mocIncsUsc) {
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc });
- // Store meta information for relaxed mode
- if (ownMoc) {
- ownMocUscIncluded = true;
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but the header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
-
- // Process <BASE>.moc includes
- for (const MocInclude& mocInc : mocIncsDot) {
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- if (wrk.Moc().RelaxedMode) {
- // Relaxed mode
- if (!ownMacro.empty() && ownMoc) {
- // Add self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- } else {
- // In relaxed mode try to find a header instead but issue a warning.
- // This is for KDE4 compatibility
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc });
- if (ownMacro.empty()) {
- if (ownMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for a compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += " instead of ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a "
- "matching header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- } else {
- // Strict mode
- if (ownMoc) {
- // Include self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- // Accept but issue a warning if moc isn't required
- if (ownMacro.empty()) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- } else {
- // Don't allow <BASE>.moc include other than self in strict mode
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nThis is not supported. Include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " to run moc on this source file.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- }
-
- if (!ownMacro.empty() && !ownDotMocIncluded) {
- // In this case, check whether the scanned file itself contains a
- // Q_OBJECT.
- // If this is the case, the moc_foo.cpp should probably be generated from
- // foo.cpp instead of foo.h, because otherwise it won't build.
- // But warn, since this is not how it is supposed to be used.
- // This is for KDE4 compatibility.
- if (wrk.Moc().RelaxedMode && ownMocUscIncluded) {
- JobPre uscJobPre;
- // Remove underscore job request
- {
- auto itC = jobs.begin();
- auto itE = jobs.end();
- for (; itC != itE; ++itC) {
- JobPre& job(*itC);
- if (job.self && job.underscore) {
- uscJobPre = std::move(job);
- jobs.erase(itC);
- break;
- }
- }
- }
- // Issue a warning
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += ". Instead it includes ";
- emsg += Quoted(uscJobPre.IncludeString);
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(FileName);
- emsg += "!\nBetter include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- // Add own source job
- jobs.emplace_back(
- JobPre{ true, false, FileName, uscJobPre.IncludeString });
- } else {
- // Otherwise always error out since it will not compile.
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += "!\nConsider to\n - add #include \"";
- emsg += meta.FileBase;
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
-
- // Convert pre jobs to actual jobs
- for (JobPre& jobPre : jobs) {
- JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName,
- std::move(jobPre.IncludeString)));
- if (jobPre.self) {
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- }
- if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) {
- return false;
- }
- }
- return true;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk,
- MetaT const& meta)
-{
- bool success = true;
- std::string const macroName = wrk.Moc().FindMacro(meta.Content);
- if (!macroName.empty()) {
- JobHandleT jobHandle(
- new JobMocT(std::string(FileName), std::string(), std::string()));
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- success = wrk.Gen().ParallelJobPushMoc(jobHandle);
- }
- return success;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders(
- WorkerT& wrk, std::string const& fileBase) const
-{
- std::string res = fileBase;
- res += ".{";
- res += cmJoin(wrk.Base().HeaderExtensions, ",");
- res += "}";
- return res;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader(
- WorkerT& wrk, std::string const& includerDir, std::string const& includeBase)
-{
- std::string header;
- // Search in vicinity of the source
- if (!wrk.Base().FindHeader(header, includerDir + includeBase)) {
- // Search in include directories
- for (std::string const& path : wrk.Moc().IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeBase;
- if (wrk.Base().FindHeader(header, fullPath)) {
- break;
- }
- }
- }
- // Sanitize
- if (!header.empty()) {
- header = wrk.FileSys().GetRealPath(header);
- }
- return header;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk,
- MetaT const& meta)
-{
- bool success = true;
- if (meta.Content.find("ui_") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Uic().RegExpInclude.find(contentChars, match)) {
- if (!ParseUicInclude(wrk, meta, match.match(2))) {
- success = false;
- break;
- }
- contentChars += match.end();
- }
- }
- return success;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude(
- WorkerT& wrk, MetaT const& meta, std::string&& includeString)
-{
- bool success = false;
- std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
- if (!uiInputFile.empty()) {
- if (!wrk.Uic().skipped(uiInputFile)) {
- JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName,
- std::move(includeString)));
- success = wrk.Gen().ParallelJobPushUic(jobHandle);
- } else {
- // A skipped file is successful
- success = true;
- }
- }
- return success;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile(
- WorkerT& wrk, MetaT const& meta, std::string const& includeString)
-{
- std::string res;
- std::string searchFile =
- wrk.FileSys().GetFilenameWithoutLastExtension(includeString).substr(3);
- searchFile += ".ui";
- // Collect search paths list
- std::deque<std::string> testFiles;
- {
- std::string const searchPath = wrk.FileSys().SubDirPrefix(includeString);
-
- std::string searchFileFull;
- if (!searchPath.empty()) {
- searchFileFull = searchPath;
- searchFileFull += searchFile;
- }
- // Vicinity of the source
- {
- std::string const sourcePath = meta.FileDir;
- testFiles.push_back(sourcePath + searchFile);
- if (!searchPath.empty()) {
- testFiles.push_back(sourcePath + searchFileFull);
- }
- }
- // AUTOUIC search paths
- if (!wrk.Uic().SearchPaths.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFile));
- }
- if (!searchPath.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFileFull));
- }
- }
- }
- }
-
- // Search for the .ui file!
- for (std::string const& testFile : testFiles) {
- if (wrk.FileSys().FileExists(testFile)) {
- res = wrk.FileSys().GetRealPath(testFile);
- break;
- }
- }
-
- // Log error
- if (res.empty()) {
- std::string emsg = "Could not find ";
- emsg += Quoted(searchFile);
- emsg += " in\n";
- for (std::string const& testFile : testFiles) {
- emsg += " ";
- emsg += Quoted(testFile);
- emsg += "\n";
- }
- wrk.LogFileError(GeneratorT::UIC, FileName, emsg);
- }
-
- return res;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk)
-{
- // (Re)generate moc_predefs.h on demand
- bool generate(false);
- bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs));
- if (!fileExists) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- generate = true;
- } else if (wrk.Moc().SettingsChanged) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because the settings changed.";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- generate = true;
- }
- if (generate) {
- ProcessResultT result;
- {
- // Compose command
- std::vector<std::string> cmd = wrk.Moc().PredefsCmd;
- // Add includes
- cmd.insert(cmd.end(), wrk.Moc().Includes.begin(),
- wrk.Moc().Includes.end());
- // Add definitions
- for (std::string const& def : wrk.Moc().Definitions) {
- cmd.push_back("-D" + def);
- }
- // Execute command
- if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
- std::string emsg = "The content generation command for ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
- }
- }
-
- // (Re)write predefs file only on demand
- if (!result.error()) {
- if (!fileExists ||
- wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
- if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs,
- result.StdOut)) {
- // Success
- } else {
- std::string emsg = "Writing ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.";
- wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg);
- }
- } else {
- // Touch to update the time stamp
- if (wrk.Log().Verbose()) {
- std::string msg = "Touching ";
- msg += Quoted(wrk.Moc().PredefsFileRel);
- msg += ".";
- wrk.LogInfo(GeneratorT::MOC, msg);
- }
- wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
- }
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies(
- WorkerT& wrk, std::string const& content)
-{
- wrk.Moc().FindDependencies(content, Depends);
- DependsValid = true;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk)
-{
- // Compute build file name
- if (!IncludeString.empty()) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
- } else {
- // Relative build path
- std::string relPath = wrk.FileSys().GetFilePathChecksum(SourceFile);
- relPath += "/moc_";
- relPath += wrk.FileSys().GetFilenameWithoutLastExtension(SourceFile);
-
- // Register relative file path with duplication check
- relPath = wrk.Gen().ParallelMocAutoRegister(relPath);
-
- // Absolute build path
- if (wrk.Base().MultiConfig) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += relPath;
- } else {
- BuildFile = wrk.Base().AbsoluteBuildPath(relPath);
- }
- }
-
- if (UpdateRequired(wrk)) {
- GenerateMoc(wrk);
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk)
-{
- bool const verbose = wrk.Gen().Log().Verbose();
-
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
-
- // Test if any setting changed
- if (wrk.Moc().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the MOC settings changed";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
-
- // Test if the moc_predefs file is newer
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(
- BuildFile, wrk.Moc().PredefsFileAbs, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than: ";
- reason += Quoted(wrk.Moc().PredefsFileAbs);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- }
-
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- }
-
- // Test if a dependency file is newer
- {
- // Read dependencies on demand
- if (!DependsValid) {
- std::string content;
- {
- std::string error;
- if (!wrk.FileSys().FileRead(content, SourceFile, &error)) {
- std::string emsg = "Could not read file\n ";
- emsg += Quoted(SourceFile);
- emsg += "\nrequired by moc include ";
- emsg += Quoted(IncludeString);
- emsg += " in\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += error;
- wrk.LogError(GeneratorT::MOC, emsg);
- return false;
- }
- }
- FindDependencies(wrk, content);
- }
- // Check dependency timestamps
- std::string error;
- std::string sourceDir = wrk.FileSys().SubDirPrefix(SourceFile);
- for (std::string const& depFileRel : Depends) {
- std::string depFileAbs =
- wrk.Moc().FindIncludedFile(sourceDir, depFileRel);
- if (!depFileAbs.empty()) {
- if (wrk.FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because it is older than it's dependency file ";
- reason += Quoted(depFileAbs);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- if (!error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- } else {
- std::string message = "Could not find dependency file ";
- message += Quoted(depFileRel);
- wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message);
- }
- }
- }
-
- return false;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
-{
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) {
- // Compose moc command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Moc().Executable);
- // Add options
- cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(),
- wrk.Moc().AllOptions.end());
- // Add predefs include
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- cmd.emplace_back("--include");
- cmd.push_back(wrk.Moc().PredefsFileAbs);
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
-
- // Execute moc command
- ProcessResultT result;
- if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
- // Moc command success
- // Print moc output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GeneratorT::MOC, result.StdOut);
- }
- // Notify the generator that a not included file changed (on demand)
- if (IncludeString.empty()) {
- wrk.Gen().ParallelMocAutoUpdated();
- }
- } else {
- // Moc command failed
- {
- std::string emsg = "The moc process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk)
-{
- // Compute build file name
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
-
- if (UpdateRequired(wrk)) {
- GenerateUic(wrk);
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk)
-{
- bool const verbose = wrk.Gen().Log().Verbose();
-
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
-
- // Test if the uic settings changed
- if (wrk.Uic().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the UIC settings changed";
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
-
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::UIC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
- }
-
- return false;
-}
-
-void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
-{
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) {
- // Compose uic command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Uic().Executable);
- {
- std::vector<std::string> allOpts = wrk.Uic().TargetOptions;
- auto optionIt = wrk.Uic().Options.find(SourceFile);
- if (optionIt != wrk.Uic().Options.end()) {
- UicMergeOptions(allOpts, optionIt->second,
- (wrk.Base().QtVersionMajor == 5));
- }
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
-
- ProcessResultT result;
- if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) {
- // Uic command success
- // Print uic output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GeneratorT::UIC, result.StdOut);
- }
- } else {
- // Uic command failed
- {
- std::string emsg = "The uic process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += "\nincluded by\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job)
-{
- delete job;
-}
-
-cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
- uv_loop_t* uvLoop)
- : Gen_(gen)
-{
- // Initialize uv asynchronous callback for process starting
- ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this);
- // Start thread
- Thread_ = std::thread(&WorkerT::Loop, this);
-}
-
-cmQtAutoGeneratorMocUic::WorkerT::~WorkerT()
-{
- // Join thread
- if (Thread_.joinable()) {
- Thread_.join();
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
- GeneratorT genType, std::string const& message) const
-{
- return Log().Info(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
- GeneratorT genType, std::string const& message) const
-{
- return Log().Warning(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
- GeneratorT genType, std::string const& filename,
- std::string const& message) const
-{
- return Log().WarningFile(genType, filename, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogError(
- GeneratorT genType, std::string const& message) const
-{
- Gen().ParallelRegisterJobError();
- Log().Error(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
- GeneratorT genType, std::string const& filename,
- std::string const& message) const
-{
- Gen().ParallelRegisterJobError();
- Log().ErrorFile(genType, filename, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
- GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output) const
-{
- Gen().ParallelRegisterJobError();
- Log().ErrorCommand(genType, message, command, output);
-}
-
-bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
- GeneratorT genType, ProcessResultT& result,
- std::vector<std::string> const& command)
-{
- if (command.empty()) {
- return false;
- }
-
- // Create process instance
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- Process_ = cm::make_unique<ReadOnlyProcessT>();
- Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir);
- }
-
- // Send asynchronous process start request to libuv loop
- ProcessRequest_.send();
-
- // Log command
- if (this->Log().Verbose()) {
- std::string msg = "Running command:\n";
- msg += QuotedCommand(command);
- msg += '\n';
- this->LogInfo(genType, msg);
- }
-
- // Wait until the process has been finished and destroyed
- {
- std::unique_lock<std::mutex> ulock(ProcessMutex_);
- while (Process_) {
- ProcessCondition_.wait(ulock);
- }
- }
- return !result.error();
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::Loop()
-{
- while (true) {
- Gen().WorkerSwapJob(JobHandle_);
- if (JobHandle_) {
- JobHandle_->Process(*this);
- } else {
- break;
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle)
-{
- auto& wrk = *reinterpret_cast<WorkerT*>(handle->data);
- {
- std::lock_guard<std::mutex> lock(wrk.ProcessMutex_);
- if (wrk.Process_ && !wrk.Process_->IsStarted()) {
- wrk.Process_->start(handle->loop, [&wrk] { wrk.UVProcessFinished(); });
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
-{
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- if (Process_ && Process_->IsFinished()) {
- Process_.reset();
- }
- }
- // Notify idling thread
- ProcessCondition_.notify_one();
-}
-
-cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
- : Base_(&FileSys())
- , Moc_(&FileSys())
-{
- // Precompile regular expressions
- Moc_.RegExpInclude.compile(
- "(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
- Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
-
- // Initialize libuv asynchronous iteration request
- UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
-}
-
-cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() = default;
-
-bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
-{
- // -- Meta
- Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
-
- // Utility lambdas
- auto InfoGet = [makefile](const char* key) {
- return makefile->GetSafeDefinition(key);
- };
- auto InfoGetBool = [makefile](const char* key) {
- return makefile->IsOn(key);
- };
- auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
- return list;
- };
- auto InfoGetLists =
- [makefile](const char* key) -> std::vector<std::vector<std::string>> {
- std::vector<std::vector<std::string>> lists;
- {
- std::string const value = makefile->GetSafeDefinition(key);
- std::string::size_type pos = 0;
- while (pos < value.size()) {
- std::string::size_type next = value.find(ListSep, pos);
- std::string::size_type length =
- (next != std::string::npos) ? next - pos : value.size() - pos;
- // Remove enclosing braces
- if (length >= 2) {
- std::string::const_iterator itBeg = value.begin() + (pos + 1);
- std::string::const_iterator itEnd = itBeg + (length - 2);
- {
- std::string subValue(itBeg, itEnd);
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(subValue, list);
- lists.push_back(std::move(list));
- }
- }
- pos += length;
- pos += ListSep.size();
- }
- }
- return lists;
- };
- auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += InfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- return makefile->GetSafeDefinition(key);
- }
- return std::string(valueConf);
- };
- auto InfoGetConfigList =
- [&InfoGetConfig](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
- return list;
- };
-
- // -- Read info file
- if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed");
- return false;
- }
-
- // -- Meta
- Log().RaiseVerbosity(InfoGet("AM_VERBOSITY"));
- Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
- {
- unsigned long num = Base_.NumThreads;
- if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
- num = std::max<unsigned long>(num, 1);
- num = std::min<unsigned long>(num, ParallelMax);
- Base_.NumThreads = static_cast<unsigned int>(num);
- }
- }
-
- // - Files and directories
- Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
- Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
- Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
- Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
- Base_.IncludeProjectDirsBefore =
- InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
- Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
- if (Base_.AutogenBuildDir.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(),
- "Autogen build directory missing");
- return false;
- }
- // include directory
- Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
- if (Base_.AutogenIncludeDir.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(),
- "Autogen include directory missing");
- return false;
- }
-
- // - Files
- SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
- if (SettingsFile_.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing");
- return false;
- }
-
- // - Qt environment
- {
- unsigned long qtv = Base_.QtVersionMajor;
- if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
- &qtv)) {
- Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
- }
- }
-
- // - Moc
- Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
- Moc_.Enabled = !Moc().Executable.empty();
- if (Moc().Enabled) {
- {
- auto lst = InfoGetList("AM_MOC_SKIP");
- Moc_.SkipList.insert(lst.begin(), lst.end());
- }
- Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
- Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
- Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
- Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
- for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
- Moc_.MacroFilters.emplace_back(
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
- }
- {
- auto pushFilter = [this](std::string const& key, std::string const& exp,
- std::string& error) {
- if (!key.empty()) {
- if (!exp.empty()) {
- Moc_.DependFilters.emplace_back();
- KeyExpT& filter(Moc_.DependFilters.back());
- if (filter.Exp.compile(exp)) {
- filter.Key = key;
- } else {
- error = "Regular expression compiling failed";
- }
- } else {
- error = "Regular expression is empty";
- }
- } else {
- error = "Key is empty";
- }
- if (!error.empty()) {
- error = ("AUTOMOC_DEPEND_FILTERS: " + error);
- error += "\n";
- error += " Key: ";
- error += Quoted(key);
- error += "\n";
- error += " Exp: ";
- error += Quoted(exp);
- error += "\n";
- }
- };
-
- std::string error;
- // Insert default filter for Q_PLUGIN_METADATA
- if (Base().QtVersionMajor != 4) {
- pushFilter("Q_PLUGIN_METADATA",
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"",
- error);
- }
- // Insert user defined dependency filters
- {
- std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
- if ((flts.size() % 2) == 0) {
- for (std::vector<std::string>::iterator itC = flts.begin(),
- itE = flts.end();
- itC != itE; itC += 2) {
- pushFilter(*itC, *(itC + 1), error);
- if (!error.empty()) {
- break;
- }
- }
- } else {
- Log().ErrorFile(
- GeneratorT::MOC, InfoFile(),
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
- return false;
- }
- }
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::MOC, InfoFile(), error);
- return false;
- }
- }
- Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
- // Install moc predefs job
- if (!Moc().PredefsCmd.empty()) {
- JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT());
- }
- }
-
- // - Uic
- Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
- Uic_.Enabled = !Uic().Executable.empty();
- if (Uic().Enabled) {
- {
- auto lst = InfoGetList("AM_UIC_SKIP");
- Uic_.SkipList.insert(lst.begin(), lst.end());
- }
- Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
- Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
- {
- auto sources = InfoGetList("AM_UIC_OPTIONS_FILES");
- auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS");
- // Compare list sizes
- if (sources.size() != options.size()) {
- std::ostringstream ost;
- ost << "files/options lists sizes mismatch (" << sources.size() << "/"
- << options.size() << ")";
- Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str());
- return false;
- }
- auto fitEnd = sources.cend();
- auto fit = sources.begin();
- auto oit = options.begin();
- while (fit != fitEnd) {
- Uic_.Options[*fit] = std::move(*oit);
- ++fit;
- ++oit;
- }
- }
- }
-
- // Initialize source file jobs
- {
- std::hash<std::string> stringHash;
- std::set<std::size_t> uniqueHeaders;
-
- // Add header jobs
- for (std::string& hdr : InfoGetList("AM_HEADERS")) {
- const bool moc = !Moc().skipped(hdr);
- const bool uic = !Uic().skipped(hdr);
- if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) {
- JobQueues_.Headers.emplace_back(
- new JobParseT(std::move(hdr), moc, uic, true));
- }
- }
- // Add source jobs
- {
- std::vector<std::string> sources = InfoGetList("AM_SOURCES");
- // Add header(s) for the source file
- for (std::string& src : sources) {
- const bool srcMoc = !Moc().skipped(src);
- const bool srcUic = !Uic().skipped(src);
- if (!srcMoc && !srcUic) {
- continue;
- }
- // Search for the default header file and a private header
- {
- std::array<std::string, 2> bases;
- bases[0] = FileSys().SubDirPrefix(src);
- bases[0] += FileSys().GetFilenameWithoutLastExtension(src);
- bases[1] = bases[0];
- bases[1] += "_p";
- for (std::string const& headerBase : bases) {
- std::string header;
- if (Base().FindHeader(header, headerBase)) {
- const bool moc = srcMoc && !Moc().skipped(header);
- const bool uic = srcUic && !Uic().skipped(header);
- if ((moc || uic) &&
- uniqueHeaders.emplace(stringHash(header)).second) {
- JobQueues_.Headers.emplace_back(
- new JobParseT(std::move(header), moc, uic, true));
- }
- }
- }
- }
- // Add source job
- JobQueues_.Sources.emplace_back(
- new JobParseT(std::move(src), srcMoc, srcUic));
- }
- }
- }
-
- // Init derived information
- // ------------------------
-
- // Init file path checksum generator
- FileSys().setupFilePathChecksum(
- Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
- Base().ProjectBinaryDir);
-
- // Moc variables
- if (Moc().Enabled) {
- // Mocs compilation file
- Moc_.CompFileAbs = Base().AbsoluteBuildPath("mocs_compilation.cpp");
-
- // Moc predefs file
- if (!Moc_.PredefsCmd.empty()) {
- Moc_.PredefsFileRel = "moc_predefs";
- if (Base_.MultiConfig) {
- Moc_.PredefsFileRel += '_';
- Moc_.PredefsFileRel += InfoConfig();
- }
- Moc_.PredefsFileRel += ".h";
- Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
- }
-
- // Sort include directories on demand
- if (Base().IncludeProjectDirsBefore) {
- // Move strings to temporary list
- std::list<std::string> includes;
- includes.insert(includes.end(), Moc().IncludePaths.begin(),
- Moc().IncludePaths.end());
- Moc_.IncludePaths.clear();
- Moc_.IncludePaths.reserve(includes.size());
- // Append project directories only
- {
- std::array<std::string const*, 2> const movePaths = {
- { &Base().ProjectBinaryDir, &Base().ProjectSourceDir }
- };
- for (std::string const* ppath : movePaths) {
- std::list<std::string>::iterator it = includes.begin();
- while (it != includes.end()) {
- std::string const& path = *it;
- if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
- Moc_.IncludePaths.push_back(path);
- it = includes.erase(it);
- } else {
- ++it;
- }
- }
- }
- }
- // Append remaining directories
- Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(),
- includes.end());
- }
- // Compose moc includes list
- {
- std::set<std::string> frameworkPaths;
- for (std::string const& path : Moc().IncludePaths) {
- Moc_.Includes.push_back("-I" + path);
- // Extract framework path
- if (cmHasLiteralSuffix(path, ".framework/Headers")) {
- // Go up twice to get to the framework root
- std::vector<std::string> pathComponents;
- FileSys().SplitPath(path, pathComponents);
- std::string frameworkPath = FileSys().JoinPath(
- pathComponents.begin(), pathComponents.end() - 2);
- frameworkPaths.insert(frameworkPath);
- }
- }
- // Append framework includes
- for (std::string const& path : frameworkPaths) {
- Moc_.Includes.emplace_back("-F");
- Moc_.Includes.push_back(path);
- }
- }
- // Setup single list with all options
- {
- // Add includes
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
- Moc().Includes.end());
- // Add definitions
- for (std::string const& def : Moc().Definitions) {
- Moc_.AllOptions.push_back("-D" + def);
- }
- // Add options
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
- Moc().Options.end());
- }
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorMocUic::Process()
-{
- // Run libuv event loop
- UVRequest().send();
- if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
- if (JobError_) {
- return false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle)
-{
- reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage();
-}
-
-void cmQtAutoGeneratorMocUic::PollStage()
-{
- switch (Stage_) {
- case StageT::SETTINGS_READ:
- SettingsFileRead();
- SetStage(StageT::CREATE_DIRECTORIES);
- break;
- case StageT::CREATE_DIRECTORIES:
- CreateDirectories();
- SetStage(StageT::PARSE_SOURCES);
- break;
- case StageT::PARSE_SOURCES:
- if (ThreadsStartJobs(JobQueues_.Sources)) {
- SetStage(StageT::PARSE_HEADERS);
- }
- break;
- case StageT::PARSE_HEADERS:
- if (ThreadsStartJobs(JobQueues_.Headers)) {
- SetStage(StageT::MOC_PREDEFS);
- }
- break;
- case StageT::MOC_PREDEFS:
- if (ThreadsStartJobs(JobQueues_.MocPredefs)) {
- SetStage(StageT::MOC_PROCESS);
- }
- break;
- case StageT::MOC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Moc)) {
- SetStage(StageT::MOCS_COMPILATION);
- }
- break;
- case StageT::MOCS_COMPILATION:
- if (ThreadsJobsDone()) {
- MocGenerateCompilation();
- SetStage(StageT::UIC_PROCESS);
- }
- break;
- case StageT::UIC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Uic)) {
- SetStage(StageT::SETTINGS_WRITE);
- }
- break;
- case StageT::SETTINGS_WRITE:
- SettingsFileWrite();
- SetStage(StageT::FINISH);
- break;
- case StageT::FINISH:
- if (ThreadsJobsDone()) {
- // Clear all libuv handles
- ThreadsStop();
- UVRequest().reset();
- // Set highest END stage manually
- Stage_ = StageT::END;
- }
- break;
- case StageT::END:
- break;
- }
-}
-
-void cmQtAutoGeneratorMocUic::SetStage(StageT stage)
-{
- if (JobError_) {
- stage = StageT::FINISH;
- }
- // Only allow to increase the stage
- if (Stage_ < stage) {
- Stage_ = stage;
- UVRequest().send();
- }
-}
-
-void cmQtAutoGeneratorMocUic::SettingsFileRead()
-{
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- if (Moc_.Enabled) {
- std::string str;
- str += Moc().Executable;
- str += sep;
- str += cmJoin(Moc().AllOptions, ";");
- str += sep;
- str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE";
- str += sep;
- str += cmJoin(Moc().PredefsCmd, ";");
- str += sep;
- SettingsStringMoc_ = crypt.HashString(str);
- }
- if (Uic().Enabled) {
- std::string str;
- str += Uic().Executable;
- str += sep;
- str += cmJoin(Uic().TargetOptions, ";");
- for (const auto& item : Uic().Options) {
- str += sep;
- str += item.first;
- str += sep;
- str += cmJoin(item.second, ";");
- }
- str += sep;
- SettingsStringUic_ = crypt.HashString(str);
- }
- }
-
- // Read old settings and compare
- {
- std::string content;
- if (FileSys().FileRead(content, SettingsFile_)) {
- if (Moc().Enabled) {
- if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
- Moc_.SettingsChanged = true;
- }
- }
- if (Uic().Enabled) {
- if (SettingsStringUic_ != SettingsFind(content, "uic")) {
- Uic_.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 (Moc().SettingsChanged || Uic().SettingsChanged) {
- FileSys().FileRemove(SettingsFile_);
- }
- } else {
- // Settings file read failed
- if (Moc().Enabled) {
- Moc_.SettingsChanged = true;
- }
- if (Uic().Enabled) {
- Uic_.SettingsChanged = true;
- }
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::SettingsFileWrite()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Only write if any setting changed
- if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
- if (Log().Verbose()) {
- Log().Info(GeneratorT::GEN,
- "Writing settings file " + Quoted(SettingsFile_));
- }
- // Compose settings file content
- std::string content;
- {
- auto SettingAppend = [&content](const char* key,
- std::string const& value) {
- if (!value.empty()) {
- content += key;
- content += ':';
- content += value;
- content += '\n';
- }
- };
- SettingAppend("moc", SettingsStringMoc_);
- SettingAppend("uic", SettingsStringUic_);
- }
- // Write settings file
- if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) {
- Log().ErrorFile(GeneratorT::GEN, SettingsFile_,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- FileSys().FileRemove(SettingsFile_);
- RegisterJobError();
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::CreateDirectories()
-{
- // Create AUTOGEN include directory
- if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDir)) {
- RegisterJobError();
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue)
-{
- bool done = false;
- std::size_t queueSize = queue.size();
-
- // Change the active queue
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Check if there are still unfinished jobs from the previous queue
- if (JobsRemain_ == 0) {
- if (!JobThreadsAbort_) {
- JobQueue_.swap(queue);
- JobsRemain_ = queueSize;
- } else {
- // Abort requested
- queue.clear();
- queueSize = 0;
- }
- done = true;
- }
- }
-
- if (done && (queueSize != 0)) {
- // Start new threads on demand
- if (Workers_.empty()) {
- Workers_.resize(Base().NumThreads);
- for (auto& item : Workers_) {
- item = cm::make_unique<WorkerT>(this, UVLoop());
- }
- } else {
- // Notify threads
- if (queueSize == 1) {
- JobsConditionRead_.notify_one();
- } else {
- JobsConditionRead_.notify_all();
- }
- }
- }
-
- return done;
-}
-
-void cmQtAutoGeneratorMocUic::ThreadsStop()
-{
- if (!Workers_.empty()) {
- // Clear all jobs
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- JobThreadsAbort_ = true;
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
-
- JobQueues_.Sources.clear();
- JobQueues_.Headers.clear();
- JobQueues_.MocPredefs.clear();
- JobQueues_.Moc.clear();
- JobQueues_.Uic.clear();
- }
- // Wake threads
- JobsConditionRead_.notify_all();
- // Join and clear threads
- Workers_.clear();
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ThreadsJobsDone()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- return (JobsRemain_ == 0);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle)
-{
- bool const jobProcessed(jobHandle);
- if (jobProcessed) {
- jobHandle.reset(nullptr);
- }
- {
- std::unique_lock<std::mutex> jobsLock(JobsMutex_);
- // Reduce the remaining job count and notify the libuv loop
- // when all jobs are done
- if (jobProcessed) {
- --JobsRemain_;
- if (JobsRemain_ == 0) {
- UVRequest().send();
- }
- }
- // Wait for new jobs
- while (!JobThreadsAbort_ && JobQueue_.empty()) {
- JobsConditionRead_.wait(jobsLock);
- }
- // Try to pick up a new job handle
- if (!JobThreadsAbort_ && !JobQueue_.empty()) {
- jobHandle = std::move(JobQueue_.front());
- JobQueue_.pop_front();
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::ParallelRegisterJobError()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- RegisterJobError();
-}
-
-// Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be
-// locked
-void cmQtAutoGeneratorMocUic::RegisterJobError()
-{
- JobError_ = true;
- if (!JobThreadsAbort_) {
- JobThreadsAbort_ = true;
- // Clear remaining jobs
- if (JobsRemain_ != 0) {
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle)
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Do additional tests if this is an included moc job
- const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle));
- if (!mocJob.IncludeString.empty()) {
- // Register included moc file and look for collisions
- MocIncludedFiles_.emplace(mocJob.SourceFile);
- if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) {
- // Another source file includes the same moc file!
- for (const JobHandleT& otherHandle : JobQueues_.Moc) {
- const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle));
- if (otherJob.IncludeString == mocJob.IncludeString) {
- // Check if the same moc file would be generated from different
- // source files which is an error.
- if (otherJob.SourceFile != mocJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(mocJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same moc include string ";
- error += Quoted(mocJob.IncludeString);
- error += "\nbut the moc file would be generated from different "
- "source files\n ";
- error += Quoted(mocJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error += ".\nConsider to\n"
- "- not include the \"moc_<NAME>.cpp\" file\n"
- "- add a directory prefix to a \"<NAME>.moc\" include "
- "(e.g \"sub/<NAME>.moc\")\n"
- "- rename the source file(s)\n";
- Log().Error(GeneratorT::MOC, error);
- RegisterJobError();
- }
- // Do not push this job in since the included moc file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- }
- }
- // Push job on demand
- if (pushJobHandle) {
- JobQueues_.Moc.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle)
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Look for include collisions.
- const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
- for (const JobHandleT& otherHandle : JobQueues_.Uic) {
- const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle));
- if (otherJob.IncludeString == uicJob.IncludeString) {
- // Check if the same uic file would be generated from different
- // source files which would be an error.
- if (otherJob.SourceFile != uicJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(uicJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same uic include string ";
- error += Quoted(uicJob.IncludeString);
- error += "\nbut the uic file would be generated from different "
- "source files\n ";
- error += Quoted(uicJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error +=
- ".\nConsider to\n"
- "- add a directory prefix to a \"ui_<NAME>.h\" include "
- "(e.g \"sub/ui_<NAME>.h\")\n"
- "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
- "include(s)\n";
- Log().Error(GeneratorT::UIC, error);
- RegisterJobError();
- }
- // Do not push this job in since the uic file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- if (pushJobHandle) {
- JobQueues_.Uic.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelMocIncluded(
- std::string const& sourceFile)
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
-}
-
-std::string cmQtAutoGeneratorMocUic::ParallelMocAutoRegister(
- std::string const& baseName)
-{
- std::string res;
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- res = baseName;
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- } else {
- // Append number suffix to the file name
- for (unsigned int ii = 2; ii != 1024; ++ii) {
- res = baseName;
- res += '_';
- res += std::to_string(ii);
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- break;
- }
- }
- }
- }
- return res;
-}
-
-void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated()
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- MocAutoFileUpdated_ = true;
-}
-
-void cmQtAutoGeneratorMocUic::MocGenerateCompilation()
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- if (!JobError_ && Moc().Enabled) {
- // Write mocs compilation build file
- {
- // Compose mocs compilation file content
- std::string content =
- "// This file is autogenerated. Changes will be overwritten.\n";
- if (MocAutoFiles_.empty()) {
- // Placeholder content
- content += "// No files found that require moc or the moc files are "
- "included\n";
- content += "enum some_compilers { need_more_than_nothing };\n";
- } else {
- // Valid content
- char const sbeg = Base().MultiConfig ? '<' : '"';
- char const send = Base().MultiConfig ? '>' : '"';
- for (std::string const& mocfile : MocAutoFiles_) {
- content += "#include ";
- content += sbeg;
- content += mocfile;
- content += send;
- content += '\n';
- }
- }
-
- std::string const& compAbs = Moc().CompFileAbs;
- if (FileSys().FileDiffers(compAbs, content)) {
- // Actually write mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compAbs);
- }
- if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) {
- Log().ErrorFile(GeneratorT::MOC, compAbs,
- "mocs compilation file writing failed");
- RegisterJobError();
- return;
- }
- } else if (MocAutoFileUpdated_) {
- // Only touch mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compAbs);
- }
- FileSys().Touch(compAbs);
- }
- }
- // Write mocs compilation wrapper file
- if (Base().MultiConfig) {
- }
- }
-}
diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h
deleted file mode 100644
index c22df29ab..000000000
--- a/Source/cmQtAutoGeneratorMocUic.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmQtAutoGeneratorMocUic_h
-#define cmQtAutoGeneratorMocUic_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include "cmQtAutoGen.h"
-#include "cmQtAutoGenerator.h"
-#include "cmUVHandlePtr.h"
-#include "cm_uv.h"
-#include "cmsys/RegularExpression.hxx"
-
-#include <condition_variable>
-#include <cstddef>
-#include <deque>
-#include <map>
-#include <memory> // IWYU pragma: keep
-#include <mutex>
-#include <set>
-#include <string>
-#include <thread>
-#include <utility>
-#include <vector>
-
-class cmMakefile;
-
-// @brief AUTOMOC and AUTOUIC generator
-class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator
-{
-public:
- cmQtAutoGeneratorMocUic();
- ~cmQtAutoGeneratorMocUic() override;
-
- cmQtAutoGeneratorMocUic(cmQtAutoGeneratorMocUic const&) = delete;
- cmQtAutoGeneratorMocUic& operator=(cmQtAutoGeneratorMocUic const&) = delete;
-
-public:
- // -- Types
- class WorkerT;
-
- /// @brief Search key plus regular expression pair
- ///
- struct KeyExpT
- {
- KeyExpT() = default;
-
- KeyExpT(const char* key, const char* exp)
- : Key(key)
- , Exp(exp)
- {
- }
-
- KeyExpT(std::string key, std::string const& exp)
- : Key(std::move(key))
- , Exp(exp)
- {
- }
-
- std::string Key;
- cmsys::RegularExpression Exp;
- };
-
- /// @brief Common settings
- ///
- class BaseSettingsT
- {
- public:
- // -- Volatile methods
- BaseSettingsT(FileSystem* fileSystem)
- : MultiConfig(false)
- , IncludeProjectDirsBefore(false)
- , QtVersionMajor(4)
- , NumThreads(1)
- , FileSys(fileSystem)
- {
- }
-
- BaseSettingsT(BaseSettingsT const&) = delete;
- BaseSettingsT& operator=(BaseSettingsT const&) = delete;
-
- // -- Const methods
- std::string AbsoluteBuildPath(std::string const& relativePath) const;
- bool FindHeader(std::string& header,
- std::string const& testBasePath) const;
-
- // -- Attributes
- // - Config
- bool MultiConfig;
- bool IncludeProjectDirsBefore;
- unsigned int QtVersionMajor;
- unsigned int NumThreads;
- // - Directories
- std::string ProjectSourceDir;
- std::string ProjectBinaryDir;
- std::string CurrentSourceDir;
- std::string CurrentBinaryDir;
- std::string AutogenBuildDir;
- std::string AutogenIncludeDir;
- // - Files
- std::vector<std::string> HeaderExtensions;
- // - File system
- FileSystem* FileSys;
- };
-
- /// @brief Moc settings
- ///
- class MocSettingsT
- {
- public:
- MocSettingsT(FileSystem* fileSys)
- : FileSys(fileSys)
- {
- }
-
- MocSettingsT(MocSettingsT const&) = delete;
- MocSettingsT& operator=(MocSettingsT const&) = delete;
-
- // -- Const methods
- bool skipped(std::string const& fileName) const;
- std::string FindMacro(std::string const& content) const;
- std::string MacrosString() const;
- std::string FindIncludedFile(std::string const& sourcePath,
- std::string const& includeString) const;
- void FindDependencies(std::string const& content,
- std::set<std::string>& depends) const;
-
- // -- Attributes
- bool Enabled = false;
- bool SettingsChanged = false;
- bool RelaxedMode = false;
- std::string Executable;
- std::string CompFileAbs;
- std::string PredefsFileRel;
- std::string PredefsFileAbs;
- std::set<std::string> SkipList;
- std::vector<std::string> IncludePaths;
- std::vector<std::string> Includes;
- std::vector<std::string> Definitions;
- std::vector<std::string> Options;
- std::vector<std::string> AllOptions;
- std::vector<std::string> PredefsCmd;
- std::vector<KeyExpT> DependFilters;
- std::vector<KeyExpT> MacroFilters;
- cmsys::RegularExpression RegExpInclude;
- // - File system
- FileSystem* FileSys;
- };
-
- /// @brief Uic settings
- ///
- class UicSettingsT
- {
- public:
- UicSettingsT() = default;
-
- UicSettingsT(UicSettingsT const&) = delete;
- UicSettingsT& operator=(UicSettingsT const&) = delete;
-
- // -- Const methods
- bool skipped(std::string const& fileName) const;
-
- // -- Attributes
- bool Enabled = false;
- bool SettingsChanged = false;
- std::string Executable;
- std::set<std::string> SkipList;
- std::vector<std::string> TargetOptions;
- std::map<std::string, std::vector<std::string>> Options;
- std::vector<std::string> SearchPaths;
- cmsys::RegularExpression RegExpInclude;
- };
-
- /// @brief Abstract job class for threaded processing
- ///
- class JobT
- {
- public:
- JobT() = default;
- virtual ~JobT() = default;
-
- JobT(JobT const&) = delete;
- JobT& operator=(JobT const&) = delete;
-
- // -- Abstract processing interface
- virtual void Process(WorkerT& wrk) = 0;
- };
-
- /// @brief Deleter for classes derived from Job
- ///
- struct JobDeleterT
- {
- void operator()(JobT* job);
- };
-
- // Job management types
- typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT;
- typedef std::deque<JobHandleT> JobQueueT;
-
- /// @brief Parse source job
- ///
- class JobParseT : public JobT
- {
- public:
- JobParseT(std::string&& fileName, bool moc, bool uic, bool header = false)
- : FileName(std::move(fileName))
- , AutoMoc(moc)
- , AutoUic(uic)
- , Header(header)
- {
- }
-
- private:
- struct MetaT
- {
- std::string Content;
- std::string FileDir;
- std::string FileBase;
- };
-
- void Process(WorkerT& wrk) override;
- bool ParseMocSource(WorkerT& wrk, MetaT const& meta);
- bool ParseMocHeader(WorkerT& wrk, MetaT const& meta);
- std::string MocStringHeaders(WorkerT& wrk,
- std::string const& fileBase) const;
- std::string MocFindIncludedHeader(WorkerT& wrk,
- std::string const& includerDir,
- std::string const& includeBase);
- bool ParseUic(WorkerT& wrk, MetaT const& meta);
- bool ParseUicInclude(WorkerT& wrk, MetaT const& meta,
- std::string&& includeString);
- std::string UicFindIncludedFile(WorkerT& wrk, MetaT const& meta,
- std::string const& includeString);
-
- private:
- std::string FileName;
- bool AutoMoc = false;
- bool AutoUic = false;
- bool Header = false;
- };
-
- /// @brief Generate moc_predefs
- ///
- class JobMocPredefsT : public JobT
- {
- private:
- void Process(WorkerT& wrk) override;
- };
-
- /// @brief Moc a file job
- ///
- class JobMocT : public JobT
- {
- public:
- JobMocT(std::string&& sourceFile, std::string includerFile,
- std::string&& includeString)
- : SourceFile(std::move(sourceFile))
- , IncluderFile(std::move(includerFile))
- , IncludeString(std::move(includeString))
- {
- }
-
- void FindDependencies(WorkerT& wrk, std::string const& content);
-
- private:
- void Process(WorkerT& wrk) override;
- bool UpdateRequired(WorkerT& wrk);
- void GenerateMoc(WorkerT& wrk);
-
- public:
- std::string SourceFile;
- std::string IncluderFile;
- std::string IncludeString;
- std::string BuildFile;
- bool DependsValid = false;
- std::set<std::string> Depends;
- };
-
- /// @brief Uic a file job
- ///
- class JobUicT : public JobT
- {
- public:
- JobUicT(std::string&& sourceFile, std::string includerFile,
- std::string&& includeString)
- : SourceFile(std::move(sourceFile))
- , IncluderFile(std::move(includerFile))
- , IncludeString(std::move(includeString))
- {
- }
-
- private:
- void Process(WorkerT& wrk) override;
- bool UpdateRequired(WorkerT& wrk);
- void GenerateUic(WorkerT& wrk);
-
- public:
- std::string SourceFile;
- std::string IncluderFile;
- std::string IncludeString;
- std::string BuildFile;
- };
-
- /// @brief Worker Thread
- ///
- class WorkerT
- {
- public:
- WorkerT(cmQtAutoGeneratorMocUic* gen, uv_loop_t* uvLoop);
- ~WorkerT();
-
- WorkerT(WorkerT const&) = delete;
- WorkerT& operator=(WorkerT const&) = delete;
-
- // -- Const accessors
- cmQtAutoGeneratorMocUic& Gen() const { return *Gen_; }
- Logger& Log() const { return Gen_->Log(); }
- FileSystem& FileSys() const { return Gen_->FileSys(); }
- const BaseSettingsT& Base() const { return Gen_->Base(); }
- const MocSettingsT& Moc() const { return Gen_->Moc(); }
- const UicSettingsT& Uic() const { return Gen_->Uic(); }
-
- // -- Log info
- void LogInfo(GeneratorT genType, std::string const& message) const;
- // -- Log warning
- void LogWarning(GeneratorT genType, std::string const& message) const;
- void LogFileWarning(GeneratorT genType, std::string const& filename,
- std::string const& message) const;
- // -- Log error
- void LogError(GeneratorT genType, std::string const& message) const;
- void LogFileError(GeneratorT genType, std::string const& filename,
- std::string const& message) const;
- void LogCommandError(GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command,
- std::string const& output) const;
-
- // -- External processes
- /// @brief Verbose logging version
- bool RunProcess(GeneratorT genType, ProcessResultT& result,
- std::vector<std::string> const& command);
-
- private:
- /// @brief Thread main loop
- void Loop();
-
- // -- Libuv callbacks
- static void UVProcessStart(uv_async_t* handle);
- void UVProcessFinished();
-
- private:
- // -- Generator
- cmQtAutoGeneratorMocUic* Gen_;
- // -- Job handle
- JobHandleT JobHandle_;
- // -- Process management
- std::mutex ProcessMutex_;
- cm::uv_async_ptr ProcessRequest_;
- std::condition_variable ProcessCondition_;
- std::unique_ptr<ReadOnlyProcessT> Process_;
- // -- System thread
- std::thread Thread_;
- };
-
- /// @brief Processing stage
- enum class StageT
- {
- SETTINGS_READ,
- CREATE_DIRECTORIES,
- PARSE_SOURCES,
- PARSE_HEADERS,
- MOC_PREDEFS,
- MOC_PROCESS,
- MOCS_COMPILATION,
- UIC_PROCESS,
- SETTINGS_WRITE,
- FINISH,
- END
- };
-
- // -- Const settings interface
- const BaseSettingsT& Base() const { return this->Base_; }
- const MocSettingsT& Moc() const { return this->Moc_; }
- const UicSettingsT& Uic() const { return this->Uic_; }
-
- // -- Worker thread interface
- void WorkerSwapJob(JobHandleT& jobHandle);
- // -- Parallel job processing interface
- void ParallelRegisterJobError();
- bool ParallelJobPushMoc(JobHandleT& jobHandle);
- bool ParallelJobPushUic(JobHandleT& jobHandle);
- bool ParallelMocIncluded(std::string const& sourceFile);
- std::string ParallelMocAutoRegister(std::string const& baseName);
- void ParallelMocAutoUpdated();
-
-private:
- // -- Abstract processing interface
- bool Init(cmMakefile* makefile) override;
- bool Process() override;
- // -- Process stage
- static void UVPollStage(uv_async_t* handle);
- void PollStage();
- void SetStage(StageT stage);
- // -- Settings file
- void SettingsFileRead();
- void SettingsFileWrite();
- // -- Thread processing
- bool ThreadsStartJobs(JobQueueT& queue);
- bool ThreadsJobsDone();
- void ThreadsStop();
- void RegisterJobError();
- // -- Generation
- void CreateDirectories();
- void MocGenerateCompilation();
-
-private:
- // -- Settings
- BaseSettingsT Base_;
- MocSettingsT Moc_;
- UicSettingsT Uic_;
- // -- Progress
- StageT Stage_ = StageT::SETTINGS_READ;
- // -- Job queues
- std::mutex JobsMutex_;
- struct
- {
- JobQueueT Sources;
- JobQueueT Headers;
- JobQueueT MocPredefs;
- JobQueueT Moc;
- JobQueueT Uic;
- } JobQueues_;
- JobQueueT JobQueue_;
- std::size_t volatile JobsRemain_ = 0;
- bool volatile JobError_ = false;
- bool volatile JobThreadsAbort_ = false;
- std::condition_variable JobsConditionRead_;
- // -- Moc meta
- std::set<std::string> MocIncludedStrings_;
- std::set<std::string> MocIncludedFiles_;
- std::set<std::string> MocAutoFiles_;
- bool volatile MocAutoFileUpdated_ = false;
- // -- Settings file
- std::string SettingsFile_;
- std::string SettingsStringMoc_;
- std::string SettingsStringUic_;
- // -- Threads and loops
- std::vector<std::unique_ptr<WorkerT>> Workers_;
-};
-
-#endif
diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx
deleted file mode 100644
index 021a15f18..000000000
--- a/Source/cmQtAutoGeneratorRcc.cxx
+++ /dev/null
@@ -1,672 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmQtAutoGeneratorRcc.h"
-#include "cmQtAutoGen.h"
-
-#include "cmAlgorithms.h"
-#include "cmCryptoHash.h"
-#include "cmFileLockResult.h"
-#include "cmMakefile.h"
-#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-
-// -- Class methods
-
-cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc()
-{
- // Initialize libuv asynchronous iteration request
- UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this);
-}
-
-cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() = default;
-
-bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile)
-{
- // -- Utility lambdas
- auto InfoGet = [makefile](std::string const& key) {
- return makefile->GetSafeDefinition(key);
- };
- auto InfoGetList =
- [makefile](std::string const& key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
- return list;
- };
- auto InfoGetConfig = [makefile,
- this](std::string const& key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += InfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- return makefile->GetSafeDefinition(key);
- }
- return std::string(valueConf);
- };
- auto InfoGetConfigList =
- [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
- return list;
- };
-
- // -- Read info file
- if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed");
- return false;
- }
-
- // - Configurations
- Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
- MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
-
- // - Directories
- AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
- if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Build directory empty");
- return false;
- }
-
- IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
- if (IncludeDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Include directory empty");
- return false;
- }
-
- // - Rcc executable
- RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
- RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
-
- // - Job
- LockFile_ = InfoGet("ARCC_LOCK_FILE");
- QrcFile_ = InfoGet("ARCC_SOURCE");
- QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
- QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
- RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
- RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
- Options_ = InfoGetConfigList("ARCC_OPTIONS");
- Inputs_ = InfoGetList("ARCC_INPUTS");
-
- // - Settings file
- SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
-
- // - Validity checks
- if (LockFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Lock file name missing");
- return false;
- }
- if (SettingsFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing");
- return false;
- }
- if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(),
- "Autogen build directory missing");
- return false;
- }
- if (RccExecutable_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing");
- return false;
- }
- if (QrcFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing");
- return false;
- }
- if (RccFileName_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing");
- return false;
- }
-
- // Init derived information
- // ------------------------
-
- RccFilePublic_ = AutogenBuildDir_;
- RccFilePublic_ += '/';
- RccFilePublic_ += RccPathChecksum_;
- RccFilePublic_ += '/';
- RccFilePublic_ += RccFileName_;
-
- // Compute rcc output file name
- if (IsMultiConfig()) {
- RccFileOutput_ = IncludeDir_;
- RccFileOutput_ += '/';
- RccFileOutput_ += MultiConfigOutput();
- } else {
- RccFileOutput_ = RccFilePublic_;
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorRcc::Process()
-{
- // Run libuv event loop
- UVRequest().send();
- if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
- if (Error_) {
- return false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle)
-{
- reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage();
-}
-
-void cmQtAutoGeneratorRcc::PollStage()
-{
- switch (Stage_) {
- // -- Initialize
- case StageT::SETTINGS_READ:
- if (SettingsFileRead()) {
- SetStage(StageT::TEST_QRC_RCC_FILES);
- } else {
- SetStage(StageT::FINISH);
- }
- break;
-
- // -- Change detection
- case StageT::TEST_QRC_RCC_FILES:
- if (TestQrcRccFiles()) {
- SetStage(StageT::GENERATE);
- } else {
- SetStage(StageT::TEST_RESOURCES_READ);
- }
- break;
- case StageT::TEST_RESOURCES_READ:
- if (TestResourcesRead()) {
- SetStage(StageT::TEST_RESOURCES);
- }
- break;
- case StageT::TEST_RESOURCES:
- if (TestResources()) {
- SetStage(StageT::GENERATE);
- } else {
- SetStage(StageT::TEST_INFO_FILE);
- }
- break;
- case StageT::TEST_INFO_FILE:
- TestInfoFile();
- SetStage(StageT::GENERATE_WRAPPER);
- break;
-
- // -- Generation
- case StageT::GENERATE:
- GenerateParentDir();
- SetStage(StageT::GENERATE_RCC);
- break;
- case StageT::GENERATE_RCC:
- if (GenerateRcc()) {
- SetStage(StageT::GENERATE_WRAPPER);
- }
- break;
- case StageT::GENERATE_WRAPPER:
- GenerateWrapper();
- SetStage(StageT::SETTINGS_WRITE);
- break;
-
- // -- Finalize
- case StageT::SETTINGS_WRITE:
- SettingsFileWrite();
- SetStage(StageT::FINISH);
- break;
- case StageT::FINISH:
- // Clear all libuv handles
- UVRequest().reset();
- // Set highest END stage manually
- Stage_ = StageT::END;
- break;
- case StageT::END:
- break;
- }
-}
-
-void cmQtAutoGeneratorRcc::SetStage(StageT stage)
-{
- if (Error_) {
- stage = StageT::FINISH;
- }
- // Only allow to increase the stage
- if (Stage_ < stage) {
- Stage_ = stage;
- UVRequest().send();
- }
-}
-
-std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const
-{
- static std::string const suffix = "_CMAKE_";
- std::string res;
- res += RccPathChecksum_;
- res += '/';
- res += AppendFilenameSuffix(RccFileName_, suffix);
- return res;
-}
-
-bool cmQtAutoGeneratorRcc::SettingsFileRead()
-{
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- {
- std::string str;
- str += RccExecutable_;
- str += sep;
- str += cmJoin(RccListOptions_, ";");
- str += sep;
- str += QrcFile_;
- str += sep;
- str += RccPathChecksum_;
- str += sep;
- str += RccFileName_;
- str += sep;
- str += cmJoin(Options_, ";");
- str += sep;
- str += cmJoin(Inputs_, ";");
- str += sep;
- SettingsString_ = crypt.HashString(str);
- }
- }
-
- // Make sure the settings file exists
- if (!FileSys().FileExists(SettingsFile_, true)) {
- // Touch the settings file to make sure it exists
- FileSys().Touch(SettingsFile_, true);
- }
-
- // Lock the lock file
- {
- // Make sure the lock file exists
- if (!FileSys().FileExists(LockFile_, true)) {
- if (!FileSys().Touch(LockFile_, true)) {
- Log().ErrorFile(GeneratorT::RCC, LockFile_,
- "Lock file creation failed");
- Error_ = true;
- return false;
- }
- }
- // Lock the lock file
- cmFileLockResult lockResult =
- LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
- if (!lockResult.IsOk()) {
- Log().ErrorFile(GeneratorT::RCC, LockFile_,
- "File lock failed: " + lockResult.GetOutputMessage());
- Error_ = true;
- return false;
- }
- }
-
- // Read old settings
- {
- std::string content;
- if (FileSys().FileRead(content, SettingsFile_)) {
- SettingsChanged_ = (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_) {
- FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, "");
- }
- } else {
- SettingsChanged_ = true;
- }
- }
-
- return true;
-}
-
-void cmQtAutoGeneratorRcc::SettingsFileWrite()
-{
- // Only write if any setting changed
- if (SettingsChanged_) {
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Writing settings file " + Quoted(SettingsFile_));
- }
- // Write settings file
- std::string content = "rcc:";
- content += SettingsString_;
- content += '\n';
- if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) {
- Log().ErrorFile(GeneratorT::RCC, SettingsFile_,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- FileSys().FileRemove(SettingsFile_);
- Error_ = true;
- }
- }
-
- // Unlock the lock file
- LockFileLock_.Release();
-}
-
-bool cmQtAutoGeneratorRcc::TestQrcRccFiles()
-{
- // Do basic checks if rcc generation is required
-
- // Test if the rcc output file exists
- if (!FileSys().FileExists(RccFileOutput_)) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from its source file ";
- reason += Quoted(QrcFile_);
- reason += " because it doesn't exist";
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- return Generate_;
- }
-
- // Test if the settings changed
- if (SettingsChanged_) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because the RCC settings changed";
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- return Generate_;
- }
-
- // Test if the rcc output file is older than the .qrc file
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = FileSys().FileIsOlderThan(RccFileOutput_, QrcFile_, &error);
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- }
- }
- if (isOlder) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " because it is older than ";
- reason += Quoted(QrcFile_);
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- }
- }
-
- return Generate_;
-}
-
-bool cmQtAutoGeneratorRcc::TestResourcesRead()
-{
- if (!Inputs_.empty()) {
- // Inputs are known already
- return true;
- }
-
- if (!RccListOptions_.empty()) {
- // Start a rcc list process and parse the output
- if (Process_) {
- // Process is running already
- if (Process_->IsFinished()) {
- // Process is finished
- if (!ProcessResult_.error()) {
- // Process success
- std::string parseError;
- if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr,
- Inputs_, parseError)) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, parseError);
- Error_ = true;
- }
- } else {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_,
- ProcessResult_.ErrorMessage);
- Error_ = true;
- }
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- } else {
- // Process is not finished, yet.
- return false;
- }
- } else {
- // Start a new process
- // rcc prints relative entry paths when started in the directory of the
- // qrc file with a pathless qrc file name argument.
- // This is important because on Windows absolute paths returned by rcc
- // might contain bad multibyte characters when the qrc file path
- // contains non-ASCII pcharacters.
- std::vector<std::string> cmd;
- cmd.push_back(RccExecutable_);
- cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end());
- cmd.push_back(QrcFileName_);
- // We're done here if the process fails to start
- return !StartProcess(QrcFileDir_, cmd, false);
- }
- } else {
- // rcc does not support the --list command.
- // Read the qrc file content and parse it.
- std::string qrcContent;
- if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) {
- RccListParseContent(qrcContent, Inputs_);
- }
- }
-
- if (!Inputs_.empty()) {
- // Convert relative paths to absolute paths
- RccListConvertFullPath(QrcFileDir_, Inputs_);
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorRcc::TestResources()
-{
- if (Inputs_.empty()) {
- return true;
- }
- {
- std::string error;
- for (std::string const& resFile : Inputs_) {
- // Check if the resource file exists
- if (!FileSys().FileExists(resFile)) {
- error = "Could not find the resource file\n ";
- error += Quoted(resFile);
- error += '\n';
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- break;
- }
- // Check if the resource file is newer than the build file
- if (FileSys().FileIsOlderThan(RccFileOutput_, resFile, &error)) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because it is older than ";
- reason += Quoted(resFile);
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- break;
- }
- // Print error and break on demand
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- break;
- }
- }
- }
-
- return Generate_;
-}
-
-void cmQtAutoGeneratorRcc::TestInfoFile()
-{
- // Test if the rcc output file is older than the info file
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = FileSys().FileIsOlderThan(RccFileOutput_, InfoFile(), &error);
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- }
- }
- if (isOlder) {
- if (Log().Verbose()) {
- std::string reason = "Touching ";
- reason += Quoted(RccFileOutput_);
- reason += " because it is older than ";
- reason += Quoted(InfoFile());
- Log().Info(GeneratorT::RCC, reason);
- }
- // Touch build file
- FileSys().Touch(RccFileOutput_);
- BuildFileChanged_ = true;
- }
- }
-}
-
-void cmQtAutoGeneratorRcc::GenerateParentDir()
-{
- // Make sure the parent directory exists
- if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileOutput_)) {
- Error_ = true;
- }
-}
-
-/**
- * @return True when finished
- */
-bool cmQtAutoGeneratorRcc::GenerateRcc()
-{
- if (!Generate_) {
- // Nothing to do
- return true;
- }
-
- if (Process_) {
- // Process is running already
- if (Process_->IsFinished()) {
- // Process is finished
- if (!ProcessResult_.error()) {
- // Rcc process success
- // Print rcc output
- if (!ProcessResult_.StdOut.empty()) {
- Log().Info(GeneratorT::RCC, ProcessResult_.StdOut);
- }
- BuildFileChanged_ = true;
- } else {
- // Rcc process failed
- {
- std::string emsg = "The rcc process failed to compile\n ";
- emsg += Quoted(QrcFile_);
- emsg += "\ninto\n ";
- emsg += Quoted(RccFileOutput_);
- if (ProcessResult_.error()) {
- emsg += "\n";
- emsg += ProcessResult_.ErrorMessage;
- }
- Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command,
- ProcessResult_.StdOut);
- }
- FileSys().FileRemove(RccFileOutput_);
- Error_ = true;
- }
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- } else {
- // Process is not finished, yet.
- return false;
- }
- } else {
- // Start a rcc process
- std::vector<std::string> cmd;
- cmd.push_back(RccExecutable_);
- cmd.insert(cmd.end(), Options_.begin(), Options_.end());
- cmd.emplace_back("-o");
- cmd.push_back(RccFileOutput_);
- cmd.push_back(QrcFile_);
- // We're done here if the process fails to start
- return !StartProcess(AutogenBuildDir_, cmd, true);
- }
-
- return true;
-}
-
-void cmQtAutoGeneratorRcc::GenerateWrapper()
-{
- // Generate a wrapper source file on demand
- if (IsMultiConfig()) {
- // Wrapper file content
- std::string content;
- content += "// This is an autogenerated configuration wrapper file.\n";
- content += "// Changes will be overwritten.\n";
- content += "#include <";
- content += MultiConfigOutput();
- content += ">\n";
-
- // Write content to file
- if (FileSys().FileDiffers(RccFilePublic_, content)) {
- // Write new wrapper file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Generating RCC wrapper file " + RccFilePublic_);
- }
- if (!FileSys().FileWrite(GeneratorT::RCC, RccFilePublic_, content)) {
- Log().ErrorFile(GeneratorT::RCC, RccFilePublic_,
- "RCC wrapper file writing failed");
- Error_ = true;
- }
- } else if (BuildFileChanged_) {
- // Just touch the wrapper file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Touching RCC wrapper file " + RccFilePublic_);
- }
- FileSys().Touch(RccFilePublic_);
- }
- }
-}
-
-bool cmQtAutoGeneratorRcc::StartProcess(
- std::string const& workingDirectory, std::vector<std::string> const& command,
- bool mergedOutput)
-{
- // Log command
- if (Log().Verbose()) {
- std::string msg = "Running command:\n";
- msg += QuotedCommand(command);
- msg += '\n';
- Log().Info(GeneratorT::RCC, msg);
- }
-
- // Create process handler
- Process_ = cm::make_unique<ReadOnlyProcessT>();
- Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory);
- // Start process
- if (!Process_->start(UVLoop(), [this] { UVRequest().send(); })) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage);
- Error_ = true;
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- return false;
- }
- return true;
-}
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
new file mode 100644
index 000000000..889f47db1
--- /dev/null
+++ b/Source/cmQtAutoMocUic.cxx
@@ -0,0 +1,2193 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoMocUic.h"
+
+#include <algorithm>
+#include <array>
+#include <list>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmQtAutoGen.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include "cmsys/FStream.hxx"
+
+#if defined(__APPLE__)
+# include <unistd.h>
+#endif
+
+static constexpr std::size_t MocUnderscoreLength = 4; // Length of "moc_"
+static constexpr std::size_t UiUnderscoreLength = 3; // Length of "ui_"
+
+cmQtAutoMocUic::IncludeKeyT::IncludeKeyT(std::string const& key,
+ std::size_t basePrefixLength)
+ : Key(key)
+ , Dir(SubDirPrefix(key))
+ , Base(cmSystemTools::GetFilenameWithoutLastExtension(key))
+{
+ if (basePrefixLength != 0) {
+ Base = Base.substr(basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUic::ParseCacheT::FileT::Clear()
+{
+ Moc.Macro.clear();
+ Moc.Include.Underscore.clear();
+ Moc.Include.Dot.clear();
+ Moc.Depends.clear();
+
+ Uic.Include.clear();
+ Uic.Depends.clear();
+}
+
+cmQtAutoMocUic::ParseCacheT::FileHandleT cmQtAutoMocUic::ParseCacheT::Get(
+ std::string const& fileName) const
+{
+ auto it = Map_.find(fileName);
+ if (it != Map_.end()) {
+ return it->second;
+ }
+ return FileHandleT();
+}
+
+cmQtAutoMocUic::ParseCacheT::GetOrInsertT
+cmQtAutoMocUic::ParseCacheT::GetOrInsert(std::string const& fileName)
+{
+ // Find existing entry
+ {
+ auto it = Map_.find(fileName);
+ if (it != Map_.end()) {
+ return GetOrInsertT{ it->second, false };
+ }
+ }
+
+ // Insert new entry
+ return GetOrInsertT{
+ Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
+ };
+}
+
+cmQtAutoMocUic::ParseCacheT::ParseCacheT() = default;
+cmQtAutoMocUic::ParseCacheT::~ParseCacheT() = default;
+
+void cmQtAutoMocUic::ParseCacheT::Clear()
+{
+ Map_.clear();
+}
+
+bool cmQtAutoMocUic::ParseCacheT::ReadFromFile(std::string const& fileName)
+{
+ cmsys::ifstream fin(fileName.c_str());
+ if (!fin) {
+ return false;
+ }
+ FileHandleT fileHandle;
+
+ std::string line;
+ while (std::getline(fin, line)) {
+ // Check if this an empty or a comment 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 file name line
+ if (line.front() != ' ') {
+ fileHandle = GetOrInsert(line).first;
+ continue;
+ }
+
+ // Bad line or bad file handle
+ if (!fileHandle || (line.size() < 6)) {
+ continue;
+ }
+
+ constexpr std::size_t offset = 5;
+ if (cmHasLiteralPrefix(line, " mmc:")) {
+ fileHandle->Moc.Macro = line.substr(offset);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " miu:")) {
+ fileHandle->Moc.Include.Underscore.emplace_back(line.substr(offset),
+ MocUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mid:")) {
+ fileHandle->Moc.Include.Dot.emplace_back(line.substr(offset), 0);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mdp:")) {
+ fileHandle->Moc.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " uic:")) {
+ fileHandle->Uic.Include.emplace_back(line.substr(offset),
+ UiUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " udp:")) {
+ fileHandle->Uic.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::ParseCacheT::WriteToFile(std::string const& fileName)
+{
+ cmGeneratedFileStream ofs(fileName);
+ if (!ofs) {
+ return false;
+ }
+ ofs << "# Generated by CMake. Changes will be overwritten." << std::endl;
+ for (auto const& pair : Map_) {
+ ofs << pair.first << std::endl;
+ FileT const& file = *pair.second;
+ if (!file.Moc.Macro.empty()) {
+ ofs << " mmc:" << file.Moc.Macro << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Underscore) {
+ ofs << " miu:" << item.Key << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Dot) {
+ ofs << " mid:" << item.Key << std::endl;
+ }
+ for (std::string const& item : file.Moc.Depends) {
+ ofs << " mdp:" << item << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Uic.Include) {
+ ofs << " uic:" << item.Key << std::endl;
+ }
+ for (std::string const& item : file.Uic.Depends) {
+ ofs << " udp:" << item << std::endl;
+ }
+ }
+ return ofs.Close();
+}
+
+cmQtAutoMocUic::BaseSettingsT::BaseSettingsT() = default;
+cmQtAutoMocUic::BaseSettingsT::~BaseSettingsT() = default;
+
+cmQtAutoMocUic::MocSettingsT::MocSettingsT()
+{
+ RegExpInclude.compile(
+ "(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+}
+
+cmQtAutoMocUic::MocSettingsT::~MocSettingsT() = default;
+
+bool cmQtAutoMocUic::MocSettingsT::skipped(std::string const& fileName) const
+{
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const
+{
+ std::string res;
+ const auto itB = MacroFilters.cbegin();
+ const auto itE = MacroFilters.cend();
+ const auto itL = itE - 1;
+ auto itC = itB;
+ for (; itC != itE; ++itC) {
+ // Separator
+ if (itC != itB) {
+ if (itC != itL) {
+ res += ", ";
+ } else {
+ res += " or ";
+ }
+ }
+ // Key
+ res += itC->Key;
+ }
+ return res;
+}
+
+cmQtAutoMocUic::UicSettingsT::UicSettingsT()
+{
+ RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+}
+
+cmQtAutoMocUic::UicSettingsT::~UicSettingsT() = default;
+
+bool cmQtAutoMocUic::UicSettingsT::skipped(std::string const& fileName) const
+{
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+void cmQtAutoMocUic::JobT::LogError(GenT genType,
+ std::string const& message) const
+{
+ Gen()->AbortError();
+ Gen()->Log().Error(genType, message);
+}
+
+void cmQtAutoMocUic::JobT::LogFileError(GenT genType,
+ std::string const& filename,
+ std::string const& message) const
+{
+ Gen()->AbortError();
+ Gen()->Log().ErrorFile(genType, filename, message);
+}
+
+void cmQtAutoMocUic::JobT::LogCommandError(
+ GenT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output) const
+{
+ Gen()->AbortError();
+ Gen()->Log().ErrorCommand(genType, message, command, output);
+}
+
+bool cmQtAutoMocUic::JobT::RunProcess(GenT genType,
+ cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage)
+{
+ // Log command
+ if (Log().Verbose()) {
+ std::string msg;
+ if ((infoMessage != nullptr) && !infoMessage->empty()) {
+ msg = *infoMessage;
+ if (msg.back() != '\n') {
+ msg += '\n';
+ }
+ }
+ msg += QuotedCommand(command);
+ msg += '\n';
+ Log().Info(genType, msg);
+ }
+ return cmWorkerPool::JobT::RunProcess(result, command,
+ BaseConst().AutogenBuildDir);
+}
+
+void cmQtAutoMocUic::JobMocPredefsT::Process()
+{
+ // (Re)generate moc_predefs.h on demand
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (!Update(reason.get())) {
+ return;
+ }
+ std::string const& predefsFileRel = MocConst().PredefsFileRel;
+ std::string const& predefsFileAbs = MocConst().PredefsFileAbs;
+ {
+ cmWorkerPool::ProcessResultT result;
+ {
+ // Compose command
+ std::vector<std::string> cmd = MocConst().PredefsCmd;
+ // Add includes
+ cmAppend(cmd, MocConst().Includes);
+ // Add definitions
+ for (std::string const& def : MocConst().Definitions) {
+ cmd.emplace_back("-D" + def);
+ }
+ // Execute command
+ if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
+ std::string msg = "The content generation command for ";
+ msg += Quoted(predefsFileRel);
+ msg += " failed.\n";
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
+ return;
+ }
+ }
+
+ // (Re)write predefs file only on demand
+ if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) {
+ if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) {
+ std::string msg = "Writing ";
+ msg += Quoted(predefsFileRel);
+ msg += " failed.";
+ LogFileError(GenT::MOC, predefsFileAbs, msg);
+ return;
+ }
+ } else {
+ // Touch to update the time stamp
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Touching " + Quoted(predefsFileRel));
+ }
+ if (!cmSystemTools::Touch(predefsFileAbs, false)) {
+ std::string msg = "Touching ";
+ msg += Quoted(predefsFileAbs);
+ msg += " failed.";
+ LogFileError(GenT::MOC, predefsFileAbs, msg);
+ return;
+ }
+ }
+ }
+
+ // Read file time afterwards
+ if (!MocEval().PredefsTime.Load(predefsFileAbs)) {
+ LogFileError(GenT::MOC, predefsFileAbs, "File time reading failed.");
+ return;
+ }
+}
+
+bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const
+{
+ // Test if the file exists
+ if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += ", because it doesn't exist.";
+ }
+ return true;
+ }
+
+ // Test if the settings changed
+ if (MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += ", because the moc settings changed.";
+ }
+ return true;
+ }
+
+ // Test if the executable is newer
+ {
+ std::string const& exec = MocConst().PredefsCmd.at(0);
+ cmFileTime execTime;
+ if (execTime.Load(exec)) {
+ if (MocEval().PredefsTime.Older(execTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += " because it is older than ";
+ *reason += Quoted(exec);
+ *reason += ".";
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmQtAutoMocUic::JobParseT::ReadFile()
+{
+ // Clear old parse information
+ FileHandle->ParseData->Clear();
+ std::string const& fileName = FileHandle->FileName;
+ // Write info
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, "Parsing " + Quoted(fileName));
+ }
+ // Read file content
+ {
+ std::string error;
+ if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) {
+ LogFileError(GenT::GEN, fileName, "Could not read the file: " + error);
+ return false;
+ }
+ }
+ // Warn if empty
+ if (Content.empty()) {
+ Log().WarningFile(GenT::GEN, fileName, "The file is empty.");
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::JobParseT::CreateKeys(std::vector<IncludeKeyT>& container,
+ std::set<std::string> const& source,
+ std::size_t basePrefixLength)
+{
+ if (source.empty()) {
+ return;
+ }
+ container.reserve(source.size());
+ for (std::string const& src : source) {
+ container.emplace_back(src, basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocMacro()
+{
+ for (KeyExpT const& filter : MocConst().MacroFilters) {
+ // Run a simple find string check
+ if (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)) {
+ // Keep detected macro name
+ FileHandle->ParseData->Moc.Macro = filter.Key;
+ return;
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocDependecies()
+{
+ if (MocConst().DependFilters.empty()) {
+ return;
+ }
+
+ // Find dependency strings
+ std::set<std::string> parseDepends;
+ for (KeyExpT const& filter : MocConst().DependFilters) {
+ // Run a simple find string check
+ if (Content.find(filter.Key) == std::string::npos) {
+ continue;
+ }
+ // Run the expensive regular expression check loop
+ const char* contentChars = Content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (filter.Exp.find(contentChars, match)) {
+ {
+ std::string dep = match.match(1);
+ if (!dep.empty()) {
+ parseDepends.emplace(std::move(dep));
+ }
+ }
+ contentChars += match.end();
+ }
+ }
+
+ // Store dependency strings
+ {
+ auto& Depends = FileHandle->ParseData->Moc.Depends;
+ Depends.reserve(parseDepends.size());
+ for (std::string const& item : parseDepends) {
+ Depends.emplace_back(item);
+ // Replace end of line characters in filenames
+ std::string& path = Depends.back();
+ std::replace(path.begin(), path.end(), '\n', ' ');
+ std::replace(path.begin(), path.end(), '\r', ' ');
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocIncludes()
+{
+ if (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;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ std::string incString = match.match(2);
+ std::string const incBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(incString);
+ if (cmHasLiteralPrefix(incBase, "moc_")) {
+ // moc_<BASE>.cpp
+ // Remove the moc_ part from the base name
+ underscore.emplace(std::move(incString));
+ } else {
+ // <BASE>.moc
+ dot.emplace(std::move(incString));
+ }
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ auto& Include = FileHandle->ParseData->Moc.Include;
+ CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
+ CreateKeys(Include.Dot, dot, 0);
+}
+
+void cmQtAutoMocUic::JobParseT::UicIncludes()
+{
+ if (Content.find("ui_") == std::string::npos) {
+ return;
+ }
+
+ std::set<std::string> includes;
+ {
+ const char* contentChars = Content.c_str();
+ cmsys::RegularExpression const& regExp = UicConst().RegExpInclude;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ includes.emplace(match.match(2));
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength);
+}
+
+void cmQtAutoMocUic::JobParseHeaderT::Process()
+{
+ if (!ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (FileHandle->Moc) {
+ MocMacro();
+ MocDependecies();
+ }
+ // Uic parsing
+ if (FileHandle->Uic) {
+ UicIncludes();
+ }
+}
+
+void cmQtAutoMocUic::JobParseSourceT::Process()
+{
+ if (!ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (FileHandle->Moc) {
+ MocMacro();
+ MocDependecies();
+ MocIncludes();
+ }
+ // Uic parsing
+ if (FileHandle->Uic) {
+ UicIncludes();
+ }
+}
+
+void cmQtAutoMocUic::JobEvaluateT::Process()
+{
+ // Evaluate for moc
+ if (MocConst().Enabled) {
+ // Evaluate headers
+ for (auto const& pair : BaseEval().Headers) {
+ if (!MocEvalHeader(pair.second)) {
+ return;
+ }
+ }
+ // Evaluate sources
+ for (auto const& pair : BaseEval().Sources) {
+ if (!MocEvalSource(pair.second)) {
+ return;
+ }
+ }
+ }
+ // Evaluate for uic
+ if (UicConst().Enabled) {
+ if (!UicEval(BaseEval().Headers) || !UicEval(BaseEval().Sources)) {
+ return;
+ }
+ }
+
+ // Add discovered header parse jobs
+ Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered);
+ // Add generate job after
+ Gen()->WorkerPool().EmplaceJob<JobGenerateT>();
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocEvalHeader(SourceFileHandleT source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!source->Moc) {
+ return true;
+ }
+
+ if (!parseData.Macro.empty()) {
+ // Create a new mapping
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->SourceFile = std::move(source);
+
+ // Absolute build path
+ if (BaseConst().MultiConfig) {
+ handle->OutputFile = Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
+ } else {
+ handle->OutputFile = Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
+ }
+
+ // Register mapping in headers map
+ MocRegisterMapping(handle, true);
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource(
+ SourceFileHandleT const& source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!sourceFile.Moc ||
+ (parseData.Macro.empty() && parseData.Include.Underscore.empty() &&
+ parseData.Include.Dot.empty())) {
+ return true;
+ }
+
+ std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
+ std::string const sourceBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName);
+
+ // For relaxed mode check if the own "moc_" or ".moc" file is included
+ bool const relaxedMode = MocConst().RelaxedMode;
+ bool sourceIncludesMocUnderscore = false;
+ bool sourceIncludesDotMoc = false;
+ // Check if the sources own "moc_" or ".moc" file is included
+ if (relaxedMode) {
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesMocUnderscore = true;
+ break;
+ }
+ }
+ }
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesDotMoc = true;
+ break;
+ }
+ }
+
+ // Check if this source needs to be moc processed but doesn't.
+ if (!sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ !(relaxedMode && sourceIncludesMocUnderscore)) {
+ {
+ std::string emsg = "The file contains a ";
+ emsg += Quoted(parseData.Macro);
+ emsg += " macro, but does not include ";
+ emsg += Quoted(sourceBase + ".moc");
+ emsg += "!\nConsider to\n - add #include \"";
+ emsg += sourceBase;
+ emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
+ LogFileError(GenT::MOC, sourceFile.FileName, emsg);
+ }
+ return false;
+ }
+
+ // Evaluate "moc_" includes
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ std::string const headerBase = incKey.Dir + incKey.Base;
+ SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
+ if (!header) {
+ {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nbut the header could not be found "
+ "in the following locations\n";
+ msg += MocMessageTestHeaders(headerBase);
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ }
+ return false;
+ }
+ // The include might be handled differently in relaxed mode
+ if (relaxedMode && !sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ (incKey.Base == sourceBase)) {
+ // The <BASE>.cpp file includes a Qt macro but does not include the
+ // <BASE>.moc file. In this case, the moc_<BASE>.cpp should probably
+ // be generated from <BASE>.cpp instead of <BASE>.h, because otherwise
+ // it won't build. But warn, since this is not how it is supposed to be
+ // used. This is for KDE4 compatibility.
+ {
+ // Issue a warning
+ std::string msg = "The file contains a ";
+ msg += Quoted(parseData.Macro);
+ msg += " macro, but does not include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += ".\nInstead it includes ";
+ msg += Quoted(incKey.Key);
+ msg += ".\nRunning moc on the source\n ";
+ msg += Quoted(sourceFile.FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += " for compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ continue;
+ }
+
+ // Check if header is skipped
+ if (MocConst().skipped(header->FileName)) {
+ continue;
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
+ return false;
+ }
+ }
+
+ // Evaluate ".moc" includes
+ if (relaxedMode) {
+ // Relaxed mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (ownMoc && !parseData.Macro.empty()) {
+ // Create mapping for the regular use case
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ continue;
+ }
+ // Try to find a header instead but issue a warning.
+ // This is for KDE4 compatibility.
+ std::string const headerBase = incKey.Dir + incKey.Base;
+ SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
+ if (!header) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nwhich seems to be the moc file from a different source "
+ "file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a matching header"
+ "could not be found in the following locations\n";
+ msg += MocMessageTestHeaders(headerBase);
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ return false;
+ }
+ // Check if header is skipped
+ if (MocConst().skipped(header->FileName)) {
+ continue;
+ }
+ // Issue a warning
+ if (ownMoc && parseData.Macro.empty()) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ", but does not contain a\n";
+ msg += MocConst().MacrosString();
+ msg += " macro.\nRunning moc on the header\n ";
+ msg += Quoted(header->FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += " for a compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ } else {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += " instead of ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += ".\nRunning moc on the header\n ";
+ msg += Quoted(header->FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += " for compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
+ return false;
+ }
+ }
+ } else {
+ // Strict mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (!ownMoc) {
+ // Don't allow <BASE>.moc include other than own in regular mode
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nwhich seems to be the moc file from a different "
+ "source file.\nThis is not supported. Include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += " to run moc on this source file.";
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ return false;
+ }
+ // Accept but issue a warning if moc isn't required
+ if (parseData.Macro.empty()) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ", but does not contain a ";
+ msg += MocConst().MacrosString();
+ msg += " macro.";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+cmQtAutoMocUic::SourceFileHandleT
+cmQtAutoMocUic::JobEvaluateT::MocFindIncludedHeader(
+ std::string const& includerDir, std::string const& includeBase) const
+{
+ // Search in vicinity of the source
+ {
+ SourceFileHandleT res = MocFindHeader(includerDir + includeBase);
+ if (res) {
+ return res;
+ }
+ }
+ // Search in include directories
+ for (std::string const& path : MocConst().IncludePaths) {
+ std::string testPath = path;
+ testPath += '/';
+ testPath += includeBase;
+ SourceFileHandleT res = MocFindHeader(testPath);
+ if (res) {
+ return res;
+ }
+ }
+ // Return without success
+ return SourceFileHandleT();
+}
+
+cmQtAutoMocUic::SourceFileHandleT cmQtAutoMocUic::JobEvaluateT::MocFindHeader(
+ std::string const& basePath) const
+{
+ std::string testPath;
+ testPath.reserve(basePath.size() + 8);
+ for (std::string const& ext : BaseConst().HeaderExtensions) {
+ testPath.clear();
+ testPath += basePath;
+ testPath += '.';
+ testPath += ext;
+ cmFileTime fileTime;
+ if (fileTime.Load(testPath)) {
+ // Compute real path of the file
+ testPath = cmSystemTools::GetRealPath(testPath);
+ // Return a known file if it exists already
+ {
+ auto it = BaseEval().Headers.find(testPath);
+ if (it != BaseEval().Headers.end()) {
+ return it->second;
+ }
+ }
+ // Created and return discovered file entry
+ SourceFileHandleT& res = MocEval().HeadersDiscovered[testPath];
+ if (!res) {
+ res = std::make_shared<SourceFileT>(testPath);
+ res->FileTime = fileTime;
+ res->Moc = true;
+ }
+ return res;
+ }
+ }
+ // Return without success
+ return SourceFileHandleT();
+}
+
+std::string cmQtAutoMocUic::JobEvaluateT::MocMessageTestHeaders(
+ std::string const& fileBase) const
+{
+ std::ostringstream res;
+ {
+ std::string exts = ".{";
+ exts += cmJoin(BaseConst().HeaderExtensions, ",");
+ exts += '}';
+ // Compose result string
+ res << " " << fileBase << exts << '\n';
+ for (std::string const& path : MocConst().IncludePaths) {
+ res << " " << path << '/' << fileBase << exts << '\n';
+ }
+ }
+ return res.str();
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded(
+ std::string const& includeString, SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle, bool sourceIsHeader) const
+{
+ // Check if this file is already included
+ MappingHandleT& handle = MocEval().Includes[includeString];
+ if (handle) {
+ // Check if the output file would be generated from different source files
+ if (handle->SourceFile != sourceFileHandle) {
+ std::string msg = "The source files\n ";
+ msg += Quoted(includerFileHandle->FileName);
+ msg += '\n';
+ for (auto const& item : handle->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += "contain the same include string ";
+ msg += Quoted(includeString);
+ msg += ", but\nthe moc file would be generated from different "
+ "source files\n ";
+ msg += Quoted(sourceFileHandle->FileName);
+ msg += " and\n ";
+ msg += Quoted(handle->SourceFile->FileName);
+ msg += ".\nConsider to\n"
+ " - not include the \"moc_<NAME>.cpp\" file\n"
+ " - add a directory prefix to a \"<NAME>.moc\" include "
+ "(e.g \"sub/<NAME>.moc\")\n"
+ " - rename the source file(s)\n";
+ LogError(GenT::MOC, msg);
+ return false;
+ }
+
+ // The same mapping already exists. Just add to the includers list.
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ return true;
+ }
+
+ // Create a new mapping
+ handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = std::move(sourceFileHandle);
+ handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
+
+ // Register mapping in sources/headers map
+ MocRegisterMapping(handle, sourceIsHeader);
+ return true;
+}
+
+void cmQtAutoMocUic::JobEvaluateT::MocRegisterMapping(
+ MappingHandleT mappingHandle, bool sourceIsHeader) const
+{
+ auto& regMap =
+ sourceIsHeader ? MocEval().HeaderMappings : MocEval().SourceMappings;
+ // Check if source file already gets mapped
+ auto& regHandle = regMap[mappingHandle->SourceFile->FileName];
+ if (!regHandle) {
+ // Yet unknown mapping
+ regHandle = std::move(mappingHandle);
+ } else {
+ // Mappings with include string override those without
+ if (!mappingHandle->IncludeString.empty()) {
+ regHandle = std::move(mappingHandle);
+ }
+ }
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicEval(SourceFileMapT const& fileMap)
+{
+ for (auto const& pair : fileMap) {
+ if (!UicEvalFile(pair.second)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile(
+ SourceFileHandleT sourceFileHandle)
+{
+ SourceFileT const& sourceFile = *sourceFileHandle;
+ auto const& Include = sourceFile.ParseData->Uic.Include;
+ if (!sourceFile.Uic || Include.empty()) {
+ return true;
+ }
+
+ std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
+ for (IncludeKeyT const& incKey : Include) {
+ // Find .ui file name
+ SourceFileHandleT uiFileHandle =
+ UicFindIncludedUi(sourceFile.FileName, sourceDir, incKey);
+ if (!uiFileHandle || UicConst().skipped(uiFileHandle->FileName)) {
+ continue;
+ }
+ // Register mapping
+ if (!UicRegisterMapping(incKey.Key, std::move(uiFileHandle),
+ std::move(sourceFileHandle))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping(
+ std::string const& includeString, SourceFileHandleT uiFileHandle,
+ SourceFileHandleT includerFileHandle)
+{
+ auto& Includes = Gen()->UicEval().Includes;
+ auto it = Includes.find(includeString);
+ if (it != Includes.end()) {
+ MappingHandleT const& handle = it->second;
+ if (handle->SourceFile != uiFileHandle) {
+ // The output file already gets generated - from a different .ui file!
+ std::string msg = "The source files\n ";
+ msg += Quoted(includerFileHandle->FileName);
+ msg += '\n';
+ for (auto const& item : handle->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += "contain the same include string ";
+ msg += Quoted(includeString);
+ msg += ", but\nthe uic file would be generated from different "
+ "user interface files\n ";
+ msg += Quoted(uiFileHandle->FileName);
+ msg += " and\n ";
+ msg += Quoted(handle->SourceFile->FileName);
+ msg += ".\nConsider to\n"
+ " - add a directory prefix to a \"ui_<NAME>.h\" include "
+ "(e.g \"sub/ui_<NAME>.h\")\n"
+ " - rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
+ "include(s)\n";
+ LogError(GenT::UIC, msg);
+ return false;
+ }
+ // Add includer file to existing mapping
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ } else {
+ // New mapping handle
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = std::move(uiFileHandle);
+ handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
+ // Register mapping
+ Includes.emplace(includeString, std::move(handle));
+ }
+ return true;
+}
+
+cmQtAutoMocUic::SourceFileHandleT
+cmQtAutoMocUic::JobEvaluateT::UicFindIncludedUi(
+ std::string const& sourceFile, std::string const& sourceDir,
+ IncludeKeyT const& incKey) const
+{
+ std::string searchFileName = incKey.Base;
+ searchFileName += ".ui";
+ // Collect search paths list
+ std::vector<std::string> testFiles;
+ {
+ auto& searchPaths = UicConst().SearchPaths;
+ testFiles.reserve((searchPaths.size() + 1) * 2);
+
+ // Vicinity of the source
+ testFiles.emplace_back(sourceDir + searchFileName);
+ if (!incKey.Dir.empty()) {
+ std::string path = sourceDir;
+ path += incKey.Dir;
+ path += searchFileName;
+ testFiles.emplace_back(path);
+ }
+ // AUTOUIC search paths
+ if (!searchPaths.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ std::string path = sPath;
+ path += '/';
+ path += searchFileName;
+ testFiles.emplace_back(std::move(path));
+ }
+ if (!incKey.Dir.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ std::string path = sPath;
+ path += '/';
+ path += incKey.Dir;
+ path += searchFileName;
+ testFiles.emplace_back(std::move(path));
+ }
+ }
+ }
+ }
+
+ // Search for the .ui file!
+ for (std::string const& testFile : testFiles) {
+ cmFileTime fileTime;
+ if (fileTime.Load(testFile)) {
+ // .ui file found in files system!
+ std::string realPath = cmSystemTools::GetRealPath(testFile);
+ // Get or create .ui file handle
+ SourceFileHandleT& handle = Gen()->UicEval().UiFiles[realPath];
+ if (!handle) {
+ // The file wasn't registered, yet
+ handle = std::make_shared<SourceFileT>(realPath);
+ handle->FileTime = fileTime;
+ }
+ return handle;
+ }
+ }
+
+ // Log error
+ {
+ std::string msg = "The file includes the uic file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nbut the user interface file ";
+ msg += Quoted(searchFileName);
+ msg += "\ncould not be found in the following locations\n";
+ for (std::string const& testFile : testFiles) {
+ msg += " ";
+ msg += Quoted(testFile);
+ msg += '\n';
+ }
+ LogFileError(GenT::UIC, sourceFile, msg);
+ }
+
+ return SourceFileHandleT();
+}
+
+void cmQtAutoMocUic::JobGenerateT::Process()
+{
+ // Add moc compile jobs
+ if (MocConst().Enabled) {
+ for (auto const& pair : 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);
+ }
+ if (!MocGenerate(pair.second, compFile)) {
+ return;
+ }
+ }
+ for (auto const& pair : MocEval().SourceMappings) {
+ if (!MocGenerate(pair.second, false)) {
+ return;
+ }
+ }
+
+ // Add mocs compilations job on demand
+ Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
+ }
+
+ // Add uic compile jobs
+ if (UicConst().Enabled) {
+ for (auto const& pair : Gen()->UicEval().Includes) {
+ if (!UicGenerate(pair.second)) {
+ return;
+ }
+ }
+ }
+
+ // Add finish job
+ Gen()->WorkerPool().EmplaceJob<JobFinishT>();
+}
+
+bool cmQtAutoMocUic::JobGenerateT::MocGenerate(MappingHandleT const& mapping,
+ bool compFile) const
+{
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (MocUpdate(*mapping, reason.get())) {
+ // Create the parent directory
+ if (!MakeParentDirectory(mapping->OutputFile)) {
+ LogFileError(GenT::MOC, mapping->OutputFile,
+ "Could not create parent directory.");
+ return false;
+ }
+ // Add moc job
+ Gen()->WorkerPool().EmplaceJob<JobMocT>(mapping, std::move(reason));
+ // Check if a moc job for a mocs_compilation.cpp entry was generated
+ if (compFile) {
+ MocEval().CompUpdated = true;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the output file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it doesn't exist, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if any setting changed
+ if (MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because the uic settings changed, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than its source file, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the moc_predefs file is newer
+ if (!MocConst().PredefsFileAbs.empty()) {
+ if (outputFileTime.Older(MocEval().PredefsTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than ";
+ *reason += Quoted(MocConst().PredefsFileAbs);
+ *reason += ", from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+ }
+
+ // Test if the moc executable is newer
+ if (outputFileTime.Older(MocConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than the moc executable, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if a dependency file is newer
+ {
+ // Check dependency timestamps
+ std::string const sourceDir = SubDirPrefix(sourceFile);
+ for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) {
+ // Find dependency file
+ auto const depMatch = MocFindDependency(sourceDir, dep);
+ if (depMatch.first.empty()) {
+ Log().WarningFile(GenT::MOC, sourceFile,
+ "Could not find dependency file " + Quoted(dep));
+ continue;
+ }
+ // Test if dependency file is older
+ if (outputFileTime.Older(depMatch.second)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than its dependency file ";
+ *reason += Quoted(depMatch.first);
+ *reason += ", from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+std::pair<std::string, cmFileTime>
+cmQtAutoMocUic::JobGenerateT::MocFindDependency(
+ std::string const& sourceDir, std::string const& includeString) const
+{
+ typedef std::pair<std::string, cmFileTime> ResPair;
+ // Search in vicinity of the source
+ {
+ ResPair res{ sourceDir + includeString, {} };
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Search in include directories
+ for (std::string const& includePath : MocConst().IncludePaths) {
+ ResPair res{ includePath, {} };
+ res.first += '/';
+ res.first += includeString;
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Return empty
+ return ResPair();
+}
+
+bool cmQtAutoMocUic::JobGenerateT::UicGenerate(
+ MappingHandleT const& mapping) const
+{
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (UicUpdate(*mapping, reason.get())) {
+ // Create the parent directory
+ if (!MakeParentDirectory(mapping->OutputFile)) {
+ LogFileError(GenT::UIC, mapping->OutputFile,
+ "Could not create parent directory.");
+ return false;
+ }
+ // Add uic job
+ Gen()->WorkerPool().EmplaceJob<JobUicT>(mapping, std::move(reason));
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the build file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it doesn't exist, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the uic settings changed
+ if (UicConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because the uic settings changed, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += " because it's older than the source file ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the uic executable is newer
+ if (outputFileTime.Older(UicConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than the uic executable, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void cmQtAutoMocUic::JobMocT::Process()
+{
+ std::string const& sourceFile = Mapping->SourceFile->FileName;
+ std::string const& outputFile = Mapping->OutputFile;
+
+ // Compose moc command
+ std::vector<std::string> cmd;
+ cmd.push_back(MocConst().Executable);
+ // Add options
+ cmAppend(cmd, MocConst().AllOptions);
+ // Add predefs include
+ if (!MocConst().PredefsFileAbs.empty()) {
+ cmd.emplace_back("--include");
+ cmd.push_back(MocConst().PredefsFileAbs);
+ }
+ cmd.emplace_back("-o");
+ cmd.push_back(outputFile);
+ cmd.push_back(sourceFile);
+
+ // Execute moc command
+ cmWorkerPool::ProcessResultT result;
+ if (RunProcess(GenT::MOC, result, cmd, Reason.get())) {
+ // Moc command success. Print moc output.
+ if (!result.StdOut.empty()) {
+ Log().Info(GenT::MOC, result.StdOut);
+ }
+ } else {
+ // Moc command failed
+ std::string msg = "The moc process failed to compile\n ";
+ msg += Quoted(sourceFile);
+ msg += "\ninto\n ";
+ msg += Quoted(outputFile);
+ if (Mapping->IncluderFiles.empty()) {
+ msg += ".\n";
+ } else {
+ msg += "\nincluded by\n";
+ for (auto const& item : Mapping->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ }
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
+ }
+}
+
+void cmQtAutoMocUic::JobUicT::Process()
+{
+ std::string const& sourceFile = Mapping->SourceFile->FileName;
+ std::string const& outputFile = Mapping->OutputFile;
+
+ // Compose uic command
+ std::vector<std::string> cmd;
+ cmd.push_back(UicConst().Executable);
+ {
+ std::vector<std::string> allOpts = UicConst().TargetOptions;
+ auto optionIt = UicConst().Options.find(sourceFile);
+ if (optionIt != UicConst().Options.end()) {
+ UicMergeOptions(allOpts, optionIt->second,
+ (BaseConst().QtVersionMajor == 5));
+ }
+ cmAppend(cmd, allOpts);
+ }
+ cmd.emplace_back("-o");
+ cmd.emplace_back(outputFile);
+ cmd.emplace_back(sourceFile);
+
+ cmWorkerPool::ProcessResultT result;
+ if (RunProcess(GenT::UIC, result, cmd, Reason.get())) {
+ // Uic command success
+ // Print uic output
+ if (!result.StdOut.empty()) {
+ Log().Info(GenT::UIC, result.StdOut);
+ }
+ } else {
+ // Uic command failed
+ std::string msg = "The uic process failed to compile\n ";
+ msg += Quoted(sourceFile);
+ msg += "\ninto\n ";
+ msg += Quoted(outputFile);
+ msg += "\nincluded by\n";
+ for (auto const& item : Mapping->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::UIC, msg, cmd, result.StdOut);
+ }
+}
+
+void cmQtAutoMocUic::JobMocsCompilationT::Process()
+{
+ // Compose mocs compilation file content
+ std::string content =
+ "// This file is autogenerated. Changes will be overwritten.\n";
+
+ if (MocEval().CompFiles.empty()) {
+ // Placeholder content
+ content += "// No files found that require moc or the moc files are "
+ "included\n";
+ content += "enum some_compilers { need_more_than_nothing };\n";
+ } else {
+ // Valid content
+ char const clampB = BaseConst().MultiConfig ? '<' : '"';
+ char const clampE = BaseConst().MultiConfig ? '>' : '"';
+ for (std::string const& mocfile : MocEval().CompFiles) {
+ content += "#include ";
+ content += clampB;
+ content += mocfile;
+ content += clampE;
+ content += '\n';
+ }
+ }
+
+ std::string const& compAbs = MocConst().CompFileAbs;
+ if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
+ // Actually write mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs);
+ }
+ if (!FileWrite(compAbs, content)) {
+ LogFileError(GenT::MOC, compAbs,
+ "mocs compilation file writing failed.");
+ }
+ } else if (MocEval().CompUpdated) {
+ // Only touch mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs);
+ }
+ if (!cmSystemTools::Touch(compAbs, false)) {
+ LogFileError(GenT::MOC, compAbs,
+ "mocs compilation file touching failed.");
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobFinishT::Process()
+{
+ Gen()->AbortSuccess();
+}
+
+cmQtAutoMocUic::cmQtAutoMocUic() = default;
+cmQtAutoMocUic::~cmQtAutoMocUic() = default;
+
+bool cmQtAutoMocUic::Init(cmMakefile* makefile)
+{
+ // Utility lambdas
+ auto InfoGet = [makefile](const char* key) {
+ return makefile->GetSafeDefinition(key);
+ };
+ auto InfoGetBool = [makefile](const char* key) {
+ return makefile->IsOn(key);
+ };
+ auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+ return list;
+ };
+ auto InfoGetLists =
+ [makefile](const char* key) -> std::vector<std::vector<std::string>> {
+ std::vector<std::vector<std::string>> lists;
+ {
+ std::string const value = makefile->GetSafeDefinition(key);
+ std::string::size_type pos = 0;
+ while (pos < value.size()) {
+ std::string::size_type next = value.find(ListSep, pos);
+ std::string::size_type length =
+ (next != std::string::npos) ? next - pos : value.size() - pos;
+ // Remove enclosing braces
+ if (length >= 2) {
+ std::string::const_iterator itBeg = value.begin() + (pos + 1);
+ std::string::const_iterator itEnd = itBeg + (length - 2);
+ {
+ std::string subValue(itBeg, itEnd);
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(subValue, list);
+ lists.push_back(std::move(list));
+ }
+ }
+ pos += length;
+ pos += ListSep.size();
+ }
+ }
+ return lists;
+ };
+ auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
+ const char* valueConf = nullptr;
+ {
+ std::string keyConf = key;
+ keyConf += '_';
+ keyConf += InfoConfig();
+ valueConf = makefile->GetDefinition(keyConf);
+ }
+ if (valueConf == nullptr) {
+ return makefile->GetSafeDefinition(key);
+ }
+ return std::string(valueConf);
+ };
+ auto InfoGetConfigList =
+ [&InfoGetConfig](const char* key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+ return list;
+ };
+ auto LogInfoError = [this](std::string const& msg) -> bool {
+ std::ostringstream err;
+ err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
+ this->Log().Error(GenT::GEN, err.str());
+ return false;
+ };
+ auto MatchSizes = [&LogInfoError](const char* keyA, const char* keyB,
+ std::size_t sizeA,
+ std::size_t sizeB) -> bool {
+ if (sizeA == sizeB) {
+ return true;
+ }
+ std::ostringstream err;
+ err << "Lists sizes mismatch " << keyA << '(' << sizeA << ") " << keyB
+ << '(' << sizeB << ')';
+ return LogInfoError(err.str());
+ };
+
+ // -- Read info file
+ if (!makefile->ReadListFile(InfoFile())) {
+ return LogInfoError("File processing failed");
+ }
+
+ // -- Meta
+ Logger_.RaiseVerbosity(InfoGet("AM_VERBOSITY"));
+ BaseConst_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
+ {
+ unsigned long num = 1;
+ if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
+ num = std::max<unsigned long>(num, 1);
+ num = std::min<unsigned long>(num, ParallelMax);
+ }
+ WorkerPool_.SetThreadCount(static_cast<unsigned int>(num));
+ }
+ BaseConst_.HeaderExtensions =
+ makefile->GetCMakeInstance()->GetHeaderExtensions();
+
+ // - Files and directories
+ BaseConst_.IncludeProjectDirsBefore =
+ InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
+ BaseConst_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
+ BaseConst_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
+ BaseConst_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
+ BaseConst_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
+ BaseConst_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
+ if (BaseConst_.AutogenBuildDir.empty()) {
+ return LogInfoError("Autogen build directory missing.");
+ }
+ BaseConst_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
+ if (BaseConst_.AutogenIncludeDir.empty()) {
+ return LogInfoError("Autogen include directory missing.");
+ }
+ BaseConst_.CMakeExecutable = InfoGetConfig("AM_CMAKE_EXECUTABLE");
+ if (BaseConst_.CMakeExecutable.empty()) {
+ return LogInfoError("CMake executable file name missing.");
+ }
+ if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) {
+ std::string error = "The CMake executable ";
+ error += Quoted(BaseConst_.CMakeExecutable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ BaseConst_.ParseCacheFile = InfoGetConfig("AM_PARSE_CACHE_FILE");
+ if (BaseConst_.ParseCacheFile.empty()) {
+ return LogInfoError("Parse cache file name missing.");
+ }
+
+ // - Settings file
+ SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
+ if (SettingsFile_.empty()) {
+ return LogInfoError("Settings file name missing.");
+ }
+
+ // - Qt environment
+ {
+ unsigned long qtv = BaseConst_.QtVersionMajor;
+ if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
+ &qtv)) {
+ BaseConst_.QtVersionMajor = static_cast<unsigned int>(qtv);
+ }
+ }
+
+ // - Moc
+ MocConst_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
+ if (!MocConst().Executable.empty()) {
+ MocConst_.Enabled = true;
+ // Load the executable file time
+ if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) {
+ std::string error = "The moc executable ";
+ error += Quoted(MocConst_.Executable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
+ MocConst_.SkipList.insert(std::move(sfl));
+ }
+ MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
+ MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
+ MocConst_.Options = InfoGetList("AM_MOC_OPTIONS");
+ MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
+ for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
+ MocConst_.MacroFilters.emplace_back(
+ item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
+ }
+ {
+ auto addFilter = [this, &LogInfoError](std::string const& key,
+ std::string const& exp) -> bool {
+ auto filterErr = [&LogInfoError, &key, &exp](const char* err) -> bool {
+ std::ostringstream ferr;
+ ferr << "AUTOMOC_DEPEND_FILTERS: " << err << '\n';
+ ferr << " Key: " << Quoted(key) << '\n';
+ ferr << " Exp: " << Quoted(exp) << '\n';
+ return LogInfoError(ferr.str());
+ };
+ if (key.empty()) {
+ return filterErr("Key is empty");
+ }
+ if (exp.empty()) {
+ return filterErr("Regular expression is empty");
+ }
+ this->MocConst_.DependFilters.emplace_back(key, exp);
+ if (!this->MocConst_.DependFilters.back().Exp.is_valid()) {
+ return filterErr("Regular expression compiling failed");
+ }
+ return true;
+ };
+
+ // Insert default filter for Q_PLUGIN_METADATA
+ if (BaseConst().QtVersionMajor != 4) {
+ if (!addFilter("Q_PLUGIN_METADATA",
+ "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
+ "[^\\)]*FILE[ \t]*\"([^\"]+)\"")) {
+ return false;
+ }
+ }
+ // Insert user defined dependency filters
+ std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
+ if ((flts.size() % 2) != 0) {
+ return LogInfoError(
+ "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
+ }
+ for (auto itC = flts.begin(), itE = flts.end(); itC != itE; itC += 2) {
+ if (!addFilter(*itC, *(itC + 1))) {
+ return false;
+ }
+ }
+ }
+ MocConst_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
+ }
+
+ // - Uic
+ UicConst_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
+ if (!UicConst().Executable.empty()) {
+ UicConst_.Enabled = true;
+ // Load the executable file time
+ if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) {
+ std::string error = "The uic executable ";
+ error += Quoted(UicConst_.Executable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
+ UicConst_.SkipList.insert(std::move(sfl));
+ }
+ UicConst_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
+ UicConst_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
+ {
+ const char* keyFiles = "AM_UIC_OPTIONS_FILES";
+ const char* keyOpts = "AM_UIC_OPTIONS_OPTIONS";
+ auto sources = InfoGetList(keyFiles);
+ auto options = InfoGetLists(keyOpts);
+ if (!MatchSizes(keyFiles, keyOpts, sources.size(), options.size())) {
+ return false;
+ }
+ auto fitEnd = sources.cend();
+ auto fit = sources.begin();
+ auto oit = options.begin();
+ while (fit != fitEnd) {
+ UicConst_.Options[*fit] = std::move(*oit);
+ ++fit;
+ ++oit;
+ }
+ }
+ }
+
+ // - Headers and sources
+ {
+ auto makeSource =
+ [&LogInfoError](std::string const& fileName,
+ std::string const& fileFlags) -> SourceFileHandleT {
+ if (fileFlags.size() != 2) {
+ LogInfoError("Invalid file flags string size");
+ return SourceFileHandleT();
+ }
+ cmFileTime fileTime;
+ if (!fileTime.Load(fileName)) {
+ LogInfoError("The source file " + cmQtAutoGen::Quoted(fileName) +
+ " does not exist.");
+ return SourceFileHandleT();
+ }
+ SourceFileHandleT sfh = std::make_shared<SourceFileT>(fileName);
+ sfh->FileTime = fileTime;
+ sfh->Moc = (fileFlags[0] == 'M');
+ sfh->Uic = (fileFlags[1] == 'U');
+ return sfh;
+ };
+
+ // Headers
+ {
+ // Get file lists
+ const char *keyFiles = "AM_HEADERS", *keyFlags = "AM_HEADERS_FLAGS";
+ std::vector<std::string> files = InfoGetList(keyFiles);
+ std::vector<std::string> flags = InfoGetList(keyFlags);
+ std::vector<std::string> builds;
+ if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
+ return false;
+ }
+ if (MocConst().Enabled) {
+ const char* keyPaths = "AM_HEADERS_BUILD_PATHS";
+ builds = InfoGetList(keyPaths);
+ if (!MatchSizes(keyFiles, keyPaths, files.size(), builds.size())) {
+ return false;
+ }
+ }
+ // Process file lists
+ for (std::size_t ii = 0; ii != files.size(); ++ii) {
+ std::string& fileName(files[ii]);
+ SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
+ if (!sfh) {
+ return false;
+ }
+ if (MocConst().Enabled) {
+ sfh->BuildPath = std::move(builds[ii]);
+ if (sfh->BuildPath.empty()) {
+ Log().ErrorFile(GenT::GEN, this->InfoFile(),
+ "Header file build path is empty");
+ return false;
+ }
+ }
+ BaseEval().Headers.emplace(std::move(fileName), std::move(sfh));
+ }
+ }
+
+ // Sources
+ {
+ const char *keyFiles = "AM_SOURCES", *keyFlags = "AM_SOURCES_FLAGS";
+ std::vector<std::string> files = InfoGetList(keyFiles);
+ std::vector<std::string> flags = InfoGetList(keyFlags);
+ if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
+ return false;
+ }
+ // Process file lists
+ for (std::size_t ii = 0; ii != files.size(); ++ii) {
+ std::string& fileName(files[ii]);
+ SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
+ if (!sfh) {
+ return false;
+ }
+ BaseEval().Sources.emplace(std::move(fileName), std::move(sfh));
+ }
+ }
+ }
+
+ // Init derived information
+ // ------------------------
+
+ // Moc variables
+ if (MocConst().Enabled) {
+ // Mocs compilation file
+ MocConst_.CompFileAbs = AbsoluteBuildPath("mocs_compilation.cpp");
+
+ // Moc predefs file
+ if (!MocConst_.PredefsCmd.empty()) {
+ MocConst_.PredefsFileRel = "moc_predefs";
+ if (BaseConst_.MultiConfig) {
+ MocConst_.PredefsFileRel += '_';
+ MocConst_.PredefsFileRel += InfoConfig();
+ }
+ MocConst_.PredefsFileRel += ".h";
+ MocConst_.PredefsFileAbs = AbsoluteBuildPath(MocConst().PredefsFileRel);
+ }
+
+ // Sort include directories on demand
+ if (BaseConst().IncludeProjectDirsBefore) {
+ // Move strings to temporary list
+ std::list<std::string> includes(MocConst().IncludePaths.begin(),
+ MocConst().IncludePaths.end());
+ MocConst_.IncludePaths.clear();
+ MocConst_.IncludePaths.reserve(includes.size());
+ // Append project directories only
+ {
+ std::array<std::string const*, 2> const movePaths = {
+ { &BaseConst().ProjectBinaryDir, &BaseConst().ProjectSourceDir }
+ };
+ for (std::string const* ppath : movePaths) {
+ std::list<std::string>::iterator it = includes.begin();
+ while (it != includes.end()) {
+ std::string const& path = *it;
+ if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
+ MocConst_.IncludePaths.push_back(path);
+ it = includes.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+ // Append remaining directories
+ MocConst_.IncludePaths.insert(MocConst_.IncludePaths.end(),
+ includes.begin(), includes.end());
+ }
+ // Compose moc includes list
+ {
+ std::set<std::string> frameworkPaths;
+ for (std::string const& path : MocConst().IncludePaths) {
+ MocConst_.Includes.push_back("-I" + path);
+ // Extract framework path
+ if (cmHasLiteralSuffix(path, ".framework/Headers")) {
+ // Go up twice to get to the framework root
+ std::vector<std::string> pathComponents;
+ cmSystemTools::SplitPath(path, pathComponents);
+ frameworkPaths.emplace(cmSystemTools::JoinPath(
+ pathComponents.begin(), pathComponents.end() - 2));
+ }
+ }
+ // Append framework includes
+ for (std::string const& path : frameworkPaths) {
+ MocConst_.Includes.emplace_back("-F");
+ MocConst_.Includes.push_back(path);
+ }
+ }
+ // Setup single list with all options
+ {
+ // Add includes
+ MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
+ MocConst().Includes.begin(),
+ MocConst().Includes.end());
+ // Add definitions
+ for (std::string const& def : MocConst().Definitions) {
+ MocConst_.AllOptions.push_back("-D" + def);
+ }
+ // Add options
+ MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
+ MocConst().Options.begin(),
+ MocConst().Options.end());
+ }
+ }
+
+ return true;
+}
+
+template <class JOBTYPE>
+void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap)
+{
+ cmFileTime const parseCacheTime = BaseEval().ParseCacheTime;
+ ParseCacheT& parseCache = BaseEval().ParseCache;
+ for (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);
+ }
+ }
+}
+
+void cmQtAutoMocUic::InitJobs()
+{
+ // Add moc_predefs.h job
+ if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) {
+ WorkerPool().EmplaceJob<JobMocPredefsT>();
+ }
+ // Add header parse jobs
+ CreateParseJobs<JobParseHeaderT>(BaseEval().Headers);
+ // Add source parse jobs
+ CreateParseJobs<JobParseSourceT>(BaseEval().Sources);
+ // Add evaluate job
+ WorkerPool().EmplaceJob<JobEvaluateT>();
+}
+
+bool cmQtAutoMocUic::Process()
+{
+ SettingsFileRead();
+ ParseCacheRead();
+ if (!CreateDirectories()) {
+ return false;
+ }
+ InitJobs();
+ if (!WorkerPool_.Process(this)) {
+ return false;
+ }
+ if (JobError_) {
+ return false;
+ }
+ if (!ParseCacheWrite()) {
+ return false;
+ }
+ if (!SettingsFileWrite()) {
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash cryptoHash(cmCryptoHash::AlgoSHA256);
+ std::string const sep(";");
+ auto cha = [&cryptoHash, &sep](std::string const& value) {
+ cryptoHash.Append(value);
+ cryptoHash.Append(sep);
+ };
+
+ if (MocConst_.Enabled) {
+ cryptoHash.Initialize();
+ cha(MocConst().Executable);
+ for (auto const& value : MocConst().AllOptions) {
+ cha(value);
+ }
+ cha(BaseConst().IncludeProjectDirsBefore ? "TRUE" : "FALSE");
+ for (auto const& value : MocConst().PredefsCmd) {
+ cha(value);
+ }
+ for (auto const& filter : MocConst().DependFilters) {
+ cha(filter.Key);
+ }
+ for (auto const& filter : MocConst().MacroFilters) {
+ cha(filter.Key);
+ }
+ SettingsStringMoc_ = cryptoHash.FinalizeHex();
+ }
+
+ if (UicConst().Enabled) {
+ cryptoHash.Initialize();
+ cha(UicConst().Executable);
+ for (auto const& value : UicConst().TargetOptions) {
+ cha(value);
+ }
+ for (const auto& item : UicConst().Options) {
+ cha(item.first);
+ for (auto const& svalue : item.second) {
+ cha(svalue);
+ }
+ }
+ 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 (UicConst().Enabled) {
+ if (SettingsStringUic_ != SettingsFind(content, "uic")) {
+ 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_);
+ }
+ } else {
+ // Settings file read failed
+ if (MocConst().Enabled) {
+ MocConst_.SettingsChanged = true;
+ }
+ if (UicConst().Enabled) {
+ UicConst_.SettingsChanged = true;
+ }
+ }
+ }
+}
+
+bool cmQtAutoMocUic::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_));
+ }
+ // Compose settings file content
+ std::string content;
+ {
+ auto SettingAppend = [&content](const char* key,
+ std::string const& value) {
+ if (!value.empty()) {
+ content += key;
+ content += ':';
+ content += value;
+ content += '\n';
+ }
+ };
+ SettingAppend("moc", SettingsStringMoc_);
+ SettingAppend("uic", SettingsStringUic_);
+ }
+ // Write settings file
+ std::string error;
+ if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) {
+ Log().ErrorFile(GenT::GEN, SettingsFile_,
+ "Settings file writing failed. " + error);
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(SettingsFile_);
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::ParseCacheRead()
+{
+ const char* reason = nullptr;
+ // Don't read the cache if it is invalid
+ if (!BaseEval().ParseCacheTime.Load(BaseConst().ParseCacheFile)) {
+ reason = "Refreshing parse cache because it doesn't exist.";
+ } else if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+ reason = "Refreshing parse cache because the settings changed.";
+ } else if (BaseEval().ParseCacheTime.Older(
+ BaseConst().CMakeExecutableTime)) {
+ reason =
+ "Refreshing parse cache because it is older than the CMake executable.";
+ }
+
+ if (reason != nullptr) {
+ // Don't read but refresh the complete parse cache
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, reason);
+ }
+ BaseEval().ParseCacheChanged = true;
+ } else {
+ // Read parse cache
+ BaseEval().ParseCache.ReadFromFile(BaseConst().ParseCacheFile);
+ }
+}
+
+bool cmQtAutoMocUic::ParseCacheWrite()
+{
+ if (BaseEval().ParseCacheChanged) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN,
+ "Writing parse cache file " +
+ Quoted(BaseConst().ParseCacheFile));
+ }
+ if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) {
+ Log().ErrorFile(GenT::GEN, BaseConst().ParseCacheFile,
+ "Parse cache file writing failed.");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::CreateDirectories()
+{
+ // Create AUTOGEN include directory
+ if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) {
+ Log().ErrorFile(GenT::GEN, BaseConst().AutogenIncludeDir,
+ "Could not create directory.");
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::Abort(bool error)
+{
+ if (error) {
+ JobError_.store(true);
+ }
+ WorkerPool_.Abort();
+}
+
+std::string cmQtAutoMocUic::AbsoluteBuildPath(
+ std::string const& relativePath) const
+{
+ std::string res(BaseConst().AutogenBuildDir);
+ res += '/';
+ res += relativePath;
+ return res;
+}
+
+std::string cmQtAutoMocUic::AbsoluteIncludePath(
+ std::string const& relativePath) const
+{
+ std::string res(BaseConst().AutogenIncludeDir);
+ res += '/';
+ res += relativePath;
+ return res;
+}
diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h
new file mode 100644
index 000000000..8061c13e6
--- /dev/null
+++ b/Source/cmQtAutoMocUic.h
@@ -0,0 +1,576 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmQtAutoMocUic_h
+#define cmQtAutoMocUic_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTime.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+#include "cmWorkerPool.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include <atomic>
+#include <cstddef>
+#include <map>
+#include <memory> // IWYU pragma: keep
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+class cmMakefile;
+
+/** \class cmQtAutoMocUic
+ * \brief AUTOMOC and AUTOUIC generator
+ */
+class cmQtAutoMocUic : public cmQtAutoGenerator
+{
+public:
+ cmQtAutoMocUic();
+ ~cmQtAutoMocUic() override;
+
+ cmQtAutoMocUic(cmQtAutoMocUic const&) = delete;
+ cmQtAutoMocUic& operator=(cmQtAutoMocUic const&) = delete;
+
+public:
+ // -- Types
+
+ /**
+ * Search key plus regular expression pair
+ */
+ struct KeyExpT
+ {
+ KeyExpT() = default;
+
+ KeyExpT(const char* key, const char* exp)
+ : Key(key)
+ , Exp(exp)
+ {
+ }
+
+ KeyExpT(std::string key, std::string const& exp)
+ : Key(std::move(key))
+ , Exp(exp)
+ {
+ }
+
+ std::string Key;
+ cmsys::RegularExpression Exp;
+ };
+
+ /**
+ * Include string with sub parts
+ */
+ struct IncludeKeyT
+ {
+ IncludeKeyT(std::string const& key, std::size_t basePrefixLength);
+
+ std::string Key; // Full include string
+ std::string Dir; // Include directory
+ std::string Base; // Base part of the include file name
+ };
+
+ /**
+ * Source file parsing cache
+ */
+ class ParseCacheT
+ {
+ public:
+ // -- Types
+ /**
+ * Entry of the file parsing cache
+ */
+ struct FileT
+ {
+ void Clear();
+
+ struct MocT
+ {
+ std::string Macro;
+ struct IncludeT
+ {
+ std::vector<IncludeKeyT> Underscore;
+ std::vector<IncludeKeyT> Dot;
+ } Include;
+ std::vector<std::string> Depends;
+ } Moc;
+
+ struct UicT
+ {
+ std::vector<IncludeKeyT> Include;
+ std::vector<std::string> Depends;
+ } Uic;
+ };
+ typedef std::shared_ptr<FileT> FileHandleT;
+ typedef std::pair<FileHandleT, bool> GetOrInsertT;
+
+ public:
+ ParseCacheT();
+ ~ParseCacheT();
+
+ void Clear();
+
+ bool ReadFromFile(std::string const& fileName);
+ bool WriteToFile(std::string const& fileName);
+
+ //! Might return an invalid handle
+ FileHandleT Get(std::string const& fileName) const;
+ //! Always returns a valid handle
+ GetOrInsertT GetOrInsert(std::string const& fileName);
+
+ private:
+ std::unordered_map<std::string, FileHandleT> Map_;
+ };
+
+ /**
+ * Source file data
+ */
+ class SourceFileT
+ {
+ public:
+ SourceFileT(std::string fileName)
+ : FileName(std::move(fileName))
+ {
+ }
+
+ public:
+ std::string FileName;
+ cmFileTime FileTime;
+ ParseCacheT::FileHandleT ParseData;
+ std::string BuildPath;
+ bool Moc = false;
+ bool Uic = false;
+ };
+ typedef std::shared_ptr<SourceFileT> SourceFileHandleT;
+ typedef std::map<std::string, SourceFileHandleT> SourceFileMapT;
+
+ /**
+ * Meta compiler file mapping information
+ */
+ struct MappingT
+ {
+ SourceFileHandleT SourceFile;
+ std::string OutputFile;
+ std::string IncludeString;
+ std::vector<SourceFileHandleT> IncluderFiles;
+ };
+ typedef std::shared_ptr<MappingT> MappingHandleT;
+ typedef std::map<std::string, MappingHandleT> MappingMapT;
+
+ /**
+ * Common settings
+ */
+ class BaseSettingsT
+ {
+ public:
+ // -- Constructors
+ BaseSettingsT();
+ ~BaseSettingsT();
+
+ BaseSettingsT(BaseSettingsT const&) = delete;
+ BaseSettingsT& operator=(BaseSettingsT const&) = delete;
+
+ // -- Attributes
+ // - Config
+ bool MultiConfig = false;
+ bool IncludeProjectDirsBefore = false;
+ unsigned int QtVersionMajor = 4;
+ // - Directories
+ std::string ProjectSourceDir;
+ std::string ProjectBinaryDir;
+ std::string CurrentSourceDir;
+ std::string CurrentBinaryDir;
+ std::string AutogenBuildDir;
+ std::string AutogenIncludeDir;
+ // - Files
+ std::string CMakeExecutable;
+ cmFileTime CMakeExecutableTime;
+ std::string ParseCacheFile;
+ std::vector<std::string> HeaderExtensions;
+ };
+
+ /**
+ * Shared common variables
+ */
+ class BaseEvalT
+ {
+ public:
+ // -- Parse Cache
+ bool ParseCacheChanged = false;
+ cmFileTime ParseCacheTime;
+ ParseCacheT ParseCache;
+
+ // -- Sources
+ SourceFileMapT Headers;
+ SourceFileMapT Sources;
+ };
+
+ /**
+ * Moc settings
+ */
+ class MocSettingsT
+ {
+ public:
+ // -- Constructors
+ MocSettingsT();
+ ~MocSettingsT();
+
+ MocSettingsT(MocSettingsT const&) = delete;
+ MocSettingsT& operator=(MocSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+ std::string MacrosString() const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ bool RelaxedMode = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::string CompFileAbs;
+ std::string PredefsFileRel;
+ std::string PredefsFileAbs;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> IncludePaths;
+ std::vector<std::string> Includes;
+ std::vector<std::string> Definitions;
+ std::vector<std::string> Options;
+ std::vector<std::string> AllOptions;
+ std::vector<std::string> PredefsCmd;
+ std::vector<KeyExpT> DependFilters;
+ std::vector<KeyExpT> MacroFilters;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /**
+ * Moc shared variables
+ */
+ class MocEvalT
+ {
+ public:
+ // -- predefines file
+ cmFileTime PredefsTime;
+ // -- Mappings
+ MappingMapT HeaderMappings;
+ MappingMapT SourceMappings;
+ MappingMapT Includes;
+ // -- Discovered files
+ SourceFileMapT HeadersDiscovered;
+ // -- Mocs compilation
+ bool CompUpdated = false;
+ std::vector<std::string> CompFiles;
+ };
+
+ /**
+ * Uic settings
+ */
+ class UicSettingsT
+ {
+ public:
+ UicSettingsT();
+ ~UicSettingsT();
+
+ UicSettingsT(UicSettingsT const&) = delete;
+ UicSettingsT& operator=(UicSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> TargetOptions;
+ std::map<std::string, std::vector<std::string>> Options;
+ std::vector<std::string> SearchPaths;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /**
+ * Uic shared variables
+ */
+ class UicEvalT
+ {
+ public:
+ SourceFileMapT UiFiles;
+ MappingMapT Includes;
+ };
+
+ /**
+ * Abstract job class for concurrent job processing
+ */
+ class JobT : public cmWorkerPool::JobT
+ {
+ protected:
+ /**
+ * @brief Protected default constructor
+ */
+ JobT(bool fence = false)
+ : cmWorkerPool::JobT(fence)
+ {
+ }
+
+ //! Get the generator. Only valid during Process() call!
+ cmQtAutoMocUic* Gen() const
+ {
+ return static_cast<cmQtAutoMocUic*>(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(); }
+
+ // -- Error logging with automatic abort
+ void LogError(GenT genType, std::string const& message) const;
+ void LogFileError(GenT genType, std::string const& filename,
+ std::string const& message) const;
+ void LogCommandError(GenT genType, std::string const& message,
+ std::vector<std::string> const& command,
+ std::string const& output) const;
+
+ /**
+ * @brief Run an external process. Use only during Process() call!
+ */
+ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage = nullptr);
+ };
+
+ /**
+ * Fence job utility class
+ */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ void Process() override{};
+ };
+
+ /**
+ * Generate moc_predefs.h
+ */
+ class JobMocPredefsT : public JobFenceT
+ {
+ void Process() override;
+ bool Update(std::string* reason) const;
+ };
+
+ /**
+ * File parse job base class
+ */
+ class JobParseT : public JobT
+ {
+ public:
+ JobParseT(SourceFileHandleT fileHandle)
+ : FileHandle(std::move(fileHandle))
+ {
+ }
+
+ protected:
+ bool ReadFile();
+ void CreateKeys(std::vector<IncludeKeyT>& container,
+ std::set<std::string> const& source,
+ std::size_t basePrefixLength);
+ void MocMacro();
+ void MocDependecies();
+ void MocIncludes();
+ void UicIncludes();
+
+ protected:
+ SourceFileHandleT FileHandle;
+ std::string Content;
+ };
+
+ /**
+ * Header file parse job
+ */
+ class JobParseHeaderT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /**
+ * Source file parse job
+ */
+ class JobParseSourceT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /**
+ * Evaluate parsed files
+ */
+ class JobEvaluateT : public JobFenceT
+ {
+ void Process() override;
+
+ // -- Moc
+ bool MocEvalHeader(SourceFileHandleT source);
+ bool MocEvalSource(SourceFileHandleT const& source);
+ SourceFileHandleT MocFindIncludedHeader(
+ std::string const& includerDir, std::string const& includeBase) const;
+ SourceFileHandleT MocFindHeader(std::string const& basePath) const;
+ std::string MocMessageTestHeaders(std::string const& fileBase) const;
+ bool MocRegisterIncluded(std::string const& includeString,
+ SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle,
+ bool sourceIsHeader) const;
+ void MocRegisterMapping(MappingHandleT mappingHandle,
+ bool sourceIsHeader) const;
+
+ // -- Uic
+ bool UicEval(SourceFileMapT const& fileMap);
+ bool UicEvalFile(SourceFileHandleT sourceFileHandle);
+ SourceFileHandleT UicFindIncludedUi(std::string const& sourceFile,
+ std::string const& sourceDir,
+ IncludeKeyT const& incKey) const;
+ bool UicRegisterMapping(std::string const& includeString,
+ SourceFileHandleT uiFileHandle,
+ SourceFileHandleT includerFileHandle);
+ };
+
+ /**
+ * Generates moc/uic jobs
+ */
+ class JobGenerateT : public JobFenceT
+ {
+ void Process() override;
+ // -- Moc
+ bool MocGenerate(MappingHandleT const& mapping, bool compFile) const;
+ bool MocUpdate(MappingT const& mapping, std::string* reason) const;
+ std::pair<std::string, cmFileTime> MocFindDependency(
+ std::string const& sourceDir, std::string const& includeString) const;
+ // -- Uic
+ bool UicGenerate(MappingHandleT const& mapping) const;
+ bool UicUpdate(MappingT const& mapping, std::string* reason) const;
+ };
+
+ /**
+ * File compiling base job
+ */
+ class JobCompileT : public JobT
+ {
+ public:
+ JobCompileT(MappingHandleT uicMapping, std::unique_ptr<std::string> reason)
+ : Mapping(std::move(uicMapping))
+ , Reason(std::move(reason))
+ {
+ }
+
+ protected:
+ MappingHandleT Mapping;
+ std::unique_ptr<std::string> Reason;
+ };
+
+ /**
+ * moc compiles a file
+ */
+ class JobMocT : public JobCompileT
+ {
+ public:
+ using JobCompileT::JobCompileT;
+ void Process() override;
+ };
+
+ /**
+ * uic compiles a file
+ */
+ class JobUicT : public JobCompileT
+ {
+ public:
+ using JobCompileT::JobCompileT;
+ void Process() override;
+ };
+
+ /// @brief Generate mocs_compilation.cpp
+ ///
+ class JobMocsCompilationT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ /// @brief The last job
+ ///
+ class JobFinishT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ // -- Const settings interface
+ BaseSettingsT const& BaseConst() const { return this->BaseConst_; }
+ BaseEvalT& BaseEval() { return this->BaseEval_; }
+ MocSettingsT const& MocConst() const { return this->MocConst_; }
+ MocEvalT& MocEval() { return this->MocEval_; }
+ UicSettingsT const& UicConst() const { return this->UicConst_; }
+ UicEvalT& UicEval() { return this->UicEval_; }
+
+ // -- Parallel job processing interface
+ cmWorkerPool& WorkerPool() { return WorkerPool_; }
+ void AbortError() { Abort(true); }
+ void AbortSuccess() { Abort(false); }
+
+ // -- Utility
+ std::string AbsoluteBuildPath(std::string const& relativePath) const;
+ std::string AbsoluteIncludePath(std::string const& relativePath) const;
+ template <class JOBTYPE>
+ void CreateParseJobs(SourceFileMapT const& sourceMap);
+
+private:
+ // -- Utility accessors
+ Logger const& Log() const { return Logger_; }
+ // -- Abstract processing interface
+ bool Init(cmMakefile* makefile) override;
+ void InitJobs();
+ bool Process() override;
+ // -- Settings file
+ void SettingsFileRead();
+ bool SettingsFileWrite();
+ // -- Parse cache
+ void ParseCacheRead();
+ bool ParseCacheWrite();
+ // -- Thread processing
+ void Abort(bool error);
+ // -- Generation
+ bool CreateDirectories();
+
+private:
+ // -- Utility
+ Logger Logger_;
+ // -- Settings
+ BaseSettingsT BaseConst_;
+ BaseEvalT BaseEval_;
+ MocSettingsT MocConst_;
+ MocEvalT MocEval_;
+ UicSettingsT UicConst_;
+ UicEvalT UicEval_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsStringMoc_;
+ std::string SettingsStringUic_;
+ // -- Worker thread pool
+ std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false);
+ cmWorkerPool WorkerPool_;
+};
+
+#endif
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
new file mode 100644
index 000000000..20885df93
--- /dev/null
+++ b/Source/cmQtAutoRcc.cxx
@@ -0,0 +1,523 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoRcc.h"
+#include "cmQtAutoGen.h"
+
+#include <sstream>
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmFileLockResult.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+
+// -- Class methods
+
+cmQtAutoRcc::cmQtAutoRcc() = default;
+
+cmQtAutoRcc::~cmQtAutoRcc() = default;
+
+bool cmQtAutoRcc::Init(cmMakefile* makefile)
+{
+ // -- Utility lambdas
+ auto InfoGet = [makefile](std::string const& key) {
+ return makefile->GetSafeDefinition(key);
+ };
+ auto InfoGetList =
+ [makefile](std::string const& key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+ return list;
+ };
+ auto InfoGetConfig = [makefile,
+ this](std::string const& key) -> std::string {
+ const char* valueConf = nullptr;
+ {
+ std::string keyConf = key;
+ keyConf += '_';
+ keyConf += InfoConfig();
+ valueConf = makefile->GetDefinition(keyConf);
+ }
+ if (valueConf == nullptr) {
+ return makefile->GetSafeDefinition(key);
+ }
+ return std::string(valueConf);
+ };
+ auto InfoGetConfigList =
+ [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+ return list;
+ };
+ auto LogInfoError = [this](std::string const& msg) -> bool {
+ std::ostringstream err;
+ err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
+ this->Log().Error(GenT::RCC, err.str());
+ return false;
+ };
+
+ // -- Read info file
+ if (!makefile->ReadListFile(InfoFile())) {
+ return LogInfoError("File processing failed.");
+ }
+
+ // - Configurations
+ Logger_.RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
+ MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
+
+ // - Directories
+ AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
+ if (AutogenBuildDir_.empty()) {
+ return LogInfoError("Build directory empty.");
+ }
+
+ IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
+ if (IncludeDir_.empty()) {
+ return LogInfoError("Include directory empty.");
+ }
+
+ // - Rcc executable
+ RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
+ if (!RccExecutableTime_.Load(RccExecutable_)) {
+ std::string error = "The rcc executable ";
+ error += Quoted(RccExecutable_);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
+
+ // - Job
+ LockFile_ = InfoGet("ARCC_LOCK_FILE");
+ QrcFile_ = InfoGet("ARCC_SOURCE");
+ QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
+ QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
+ RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
+ RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
+ Options_ = InfoGetConfigList("ARCC_OPTIONS");
+ Inputs_ = InfoGetList("ARCC_INPUTS");
+
+ // - Settings file
+ SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
+
+ // - Validity checks
+ if (LockFile_.empty()) {
+ return LogInfoError("Lock file name missing.");
+ }
+ if (SettingsFile_.empty()) {
+ return LogInfoError("Settings file name missing.");
+ }
+ if (AutogenBuildDir_.empty()) {
+ return LogInfoError("Autogen build directory missing.");
+ }
+ if (RccExecutable_.empty()) {
+ return LogInfoError("rcc executable missing.");
+ }
+ if (QrcFile_.empty()) {
+ return LogInfoError("rcc input file missing.");
+ }
+ if (RccFileName_.empty()) {
+ return LogInfoError("rcc output file missing.");
+ }
+
+ // Init derived information
+ // ------------------------
+
+ RccFilePublic_ = AutogenBuildDir_;
+ RccFilePublic_ += '/';
+ RccFilePublic_ += RccPathChecksum_;
+ RccFilePublic_ += '/';
+ RccFilePublic_ += RccFileName_;
+
+ // Compute rcc output file name
+ if (IsMultiConfig()) {
+ RccFileOutput_ = IncludeDir_;
+ RccFileOutput_ += '/';
+ RccFileOutput_ += MultiConfigOutput();
+ } else {
+ RccFileOutput_ = RccFilePublic_;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::Process()
+{
+ if (!SettingsFileRead()) {
+ return false;
+ }
+
+ // Test if the rcc output needs to be regenerated
+ bool generate = false;
+ if (!TestQrcRccFiles(generate)) {
+ return false;
+ }
+ if (!generate && !TestResources(generate)) {
+ return false;
+ }
+ // Generate on demand
+ if (generate) {
+ if (!GenerateRcc()) {
+ return false;
+ }
+ } else {
+ // Test if the info file is newer than the output file
+ if (!TestInfoFile()) {
+ return false;
+ }
+ }
+
+ if (!GenerateWrapper()) {
+ return false;
+ }
+
+ return SettingsFileWrite();
+}
+
+std::string cmQtAutoRcc::MultiConfigOutput() const
+{
+ static std::string const suffix = "_CMAKE_";
+ std::string res;
+ res += RccPathChecksum_;
+ res += '/';
+ res += AppendFilenameSuffix(RccFileName_, suffix);
+ return res;
+}
+
+bool cmQtAutoRcc::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
+ std::string const sep(" ~~~ ");
+ {
+ std::string str;
+ str += RccExecutable_;
+ str += sep;
+ str += cmJoin(RccListOptions_, ";");
+ str += sep;
+ str += QrcFile_;
+ str += sep;
+ str += RccPathChecksum_;
+ str += sep;
+ str += RccFileName_;
+ str += sep;
+ str += cmJoin(Options_, ";");
+ str += sep;
+ str += cmJoin(Inputs_, ";");
+ str += sep;
+ SettingsString_ = crypt.HashString(str);
+ }
+ }
+
+ // Make sure the settings file exists
+ if (!cmSystemTools::FileExists(SettingsFile_, true)) {
+ // Touch the settings file to make sure it exists
+ if (!cmSystemTools::Touch(SettingsFile_, true)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file creation failed.");
+ return false;
+ }
+ }
+
+ // Lock the lock file
+ {
+ // Make sure the lock file exists
+ if (!cmSystemTools::FileExists(LockFile_, true)) {
+ if (!cmSystemTools::Touch(LockFile_, true)) {
+ Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed.");
+ return false;
+ }
+ }
+ // Lock the lock file
+ cmFileLockResult lockResult =
+ LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
+ if (!lockResult.IsOk()) {
+ Log().ErrorFile(GenT::RCC, LockFile_,
+ "File lock failed: " + lockResult.GetOutputMessage());
+ return false;
+ }
+ }
+
+ // Read old settings
+ {
+ std::string content;
+ if (FileRead(content, SettingsFile_)) {
+ SettingsChanged_ = (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_) {
+ std::string error;
+ if (!FileWrite(SettingsFile_, "", &error)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file clearing failed. " + error);
+ return false;
+ }
+ }
+ } else {
+ SettingsChanged_ = true;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_));
+ }
+ // Write settings file
+ std::string content = "rcc:";
+ content += SettingsString_;
+ content += '\n';
+ std::string error;
+ if (!FileWrite(SettingsFile_, content, &error)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file writing failed. " + error);
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(SettingsFile_);
+ return false;
+ }
+ }
+
+ // Unlock the lock file
+ LockFileLock_.Release();
+ return true;
+}
+
+/// Do basic checks if rcc generation is required
+bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
+{
+ // Test if the rcc input file exists
+ if (!QrcFileTime_.Load(QrcFile_)) {
+ std::string error;
+ error = "The resources file ";
+ error += Quoted(QrcFile_);
+ error += " does not exist";
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+
+ // Test if the rcc output file exists
+ if (!RccFileTime_.Load(RccFileOutput_)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it doesn't exist, from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the settings changed
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because the rcc settings changed, from ";
+ Reason += Quoted(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 = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(QrcFile_);
+ Reason += ", from ";
+ Reason += Quoted(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 = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than the rcc executable, from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::TestResources(bool& generate)
+{
+ // Read resource files list
+ if (Inputs_.empty()) {
+ std::string error;
+ RccLister const lister(RccExecutable_, RccListOptions_);
+ if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) {
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+ }
+
+ // Check if any resource file is newer than the rcc output file
+ for (std::string const& resFile : Inputs_) {
+ // Check if the resource file exists
+ cmFileTime fileTime;
+ if (!fileTime.Load(resFile)) {
+ std::string error;
+ error = "Could not find the resource file\n ";
+ error += Quoted(resFile);
+ error += '\n';
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+ // Check if the resource file is newer than the rcc output file
+ if (RccFileTime_.Older(fileTime)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(resFile);
+ Reason += ", from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ break;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoRcc::TestInfoFile()
+{
+ // Test if the rcc output file is older than the info file
+ if (RccFileTime_.Older(InfoFileTime())) {
+ if (Log().Verbose()) {
+ std::string reason = "Touching ";
+ reason += Quoted(RccFileOutput_);
+ reason += " because it is older than ";
+ reason += Quoted(InfoFile());
+ Log().Info(GenT::RCC, reason);
+ }
+ // Touch build file
+ if (!cmSystemTools::Touch(RccFileOutput_, false)) {
+ Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed");
+ return false;
+ }
+ BuildFileChanged_ = true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::GenerateRcc()
+{
+ // Make parent directory
+ if (!MakeParentDirectory(RccFileOutput_)) {
+ Log().ErrorFile(GenT::RCC, RccFileOutput_,
+ "Could not create parent directory");
+ return false;
+ }
+
+ // Compose rcc command
+ std::vector<std::string> cmd;
+ cmd.push_back(RccExecutable_);
+ cmAppend(cmd, Options_);
+ cmd.emplace_back("-o");
+ cmd.push_back(RccFileOutput_);
+ cmd.push_back(QrcFile_);
+
+ // Log reason and command
+ if (Log().Verbose()) {
+ std::string msg = Reason;
+ if (!msg.empty() && (msg.back() != '\n')) {
+ msg += '\n';
+ }
+ msg += QuotedCommand(cmd);
+ msg += '\n';
+ Log().Info(GenT::RCC, msg);
+ }
+
+ std::string rccStdOut;
+ std::string rccStdErr;
+ int retVal = 0;
+ bool result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ if (!result || (retVal != 0)) {
+ // rcc process failed
+ {
+ std::string err = "The rcc process failed to compile\n ";
+ err += Quoted(QrcFile_);
+ err += "\ninto\n ";
+ err += Quoted(RccFileOutput_);
+ Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr);
+ }
+ cmSystemTools::RemoveFile(RccFileOutput_);
+ return false;
+ }
+
+ // rcc process success
+ // Print rcc output
+ if (!rccStdOut.empty()) {
+ Log().Info(GenT::RCC, rccStdOut);
+ }
+ BuildFileChanged_ = true;
+
+ return true;
+}
+
+bool cmQtAutoRcc::GenerateWrapper()
+{
+ // Generate a wrapper source file on demand
+ if (IsMultiConfig()) {
+ // Wrapper file content
+ std::string content;
+ content += "// This is an autogenerated configuration wrapper file.\n";
+ content += "// Changes will be overwritten.\n";
+ content += "#include <";
+ content += MultiConfigOutput();
+ content += ">\n";
+
+ // Compare with existing file content
+ bool fileDiffers = true;
+ {
+ std::string oldContents;
+ if (FileRead(oldContents, RccFilePublic_)) {
+ fileDiffers = (oldContents != content);
+ }
+ }
+ if (fileDiffers) {
+ // Write new wrapper file
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_);
+ }
+ std::string error;
+ if (!FileWrite(RccFilePublic_, content, &error)) {
+ Log().ErrorFile(GenT::RCC, RccFilePublic_,
+ "RCC wrapper file writing failed. " + error);
+ return false;
+ }
+ } else if (BuildFileChanged_) {
+ // Just touch the wrapper file
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_);
+ }
+ if (!cmSystemTools::Touch(RccFilePublic_, false)) {
+ Log().ErrorFile(GenT::RCC, RccFilePublic_,
+ "RCC wrapper file touch failed.");
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoRcc.h
index 1ec1c4a8c..636a6672d 100644
--- a/Source/cmQtAutoGeneratorRcc.h
+++ b/Source/cmQtAutoRcc.h
@@ -1,13 +1,13 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmQtAutoGeneratorRcc_h
-#define cmQtAutoGeneratorRcc_h
+#ifndef cmQtAutoRcc_h
+#define cmQtAutoRcc_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmFileLock.h"
+#include "cmFileTime.h"
#include "cmQtAutoGenerator.h"
-#include "cm_uv.h"
#include <string>
#include <vector>
@@ -15,62 +15,38 @@
class cmMakefile;
// @brief AUTORCC generator
-class cmQtAutoGeneratorRcc : public cmQtAutoGenerator
+class cmQtAutoRcc : public cmQtAutoGenerator
{
public:
- cmQtAutoGeneratorRcc();
- ~cmQtAutoGeneratorRcc() override;
+ cmQtAutoRcc();
+ ~cmQtAutoRcc() override;
- cmQtAutoGeneratorRcc(cmQtAutoGeneratorRcc const&) = delete;
- cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete;
+ cmQtAutoRcc(cmQtAutoRcc const&) = delete;
+ cmQtAutoRcc& operator=(cmQtAutoRcc const&) = delete;
private:
- // -- Types
-
- /// @brief Processing stage
- enum class StageT : unsigned char
- {
- SETTINGS_READ,
- TEST_QRC_RCC_FILES,
- TEST_RESOURCES_READ,
- TEST_RESOURCES,
- TEST_INFO_FILE,
- GENERATE,
- GENERATE_RCC,
- GENERATE_WRAPPER,
- SETTINGS_WRITE,
- FINISH,
- END
- };
+ // -- Utility
+ Logger const& Log() const { return Logger_; }
+ bool IsMultiConfig() const { return MultiConfig_; }
+ std::string MultiConfigOutput() const;
// -- Abstract processing interface
bool Init(cmMakefile* makefile) override;
bool Process() override;
- // -- Process stage
- static void UVPollStage(uv_async_t* handle);
- void PollStage();
- void SetStage(StageT stage);
// -- Settings file
bool SettingsFileRead();
- void SettingsFileWrite();
+ bool SettingsFileWrite();
// -- Tests
- bool TestQrcRccFiles();
- bool TestResourcesRead();
- bool TestResources();
- void TestInfoFile();
+ bool TestQrcRccFiles(bool& generate);
+ bool TestResources(bool& generate);
+ bool TestInfoFile();
// -- Generation
- void GenerateParentDir();
bool GenerateRcc();
- void GenerateWrapper();
-
- // -- Utility
- bool IsMultiConfig() const { return MultiConfig_; }
- std::string MultiConfigOutput() const;
- bool StartProcess(std::string const& workingDirectory,
- std::vector<std::string> const& command,
- bool mergedOutput);
+ bool GenerateWrapper();
private:
+ // -- Logging
+ Logger Logger_;
// -- Config settings
bool MultiConfig_ = false;
// -- Directories
@@ -78,6 +54,7 @@ private:
std::string IncludeDir_;
// -- Qt environment
std::string RccExecutable_;
+ cmFileTime RccExecutableTime_;
std::vector<std::string> RccListOptions_;
// -- Job
std::string LockFile_;
@@ -85,23 +62,19 @@ private:
std::string QrcFile_;
std::string QrcFileName_;
std::string QrcFileDir_;
+ cmFileTime QrcFileTime_;
std::string RccPathChecksum_;
std::string RccFileName_;
std::string RccFileOutput_;
std::string RccFilePublic_;
+ cmFileTime RccFileTime_;
+ std::string Reason;
std::vector<std::string> Options_;
std::vector<std::string> Inputs_;
- // -- Subprocess
- ProcessResultT ProcessResult_;
- std::unique_ptr<ReadOnlyProcessT> Process_;
// -- Settings file
std::string SettingsFile_;
std::string SettingsString_;
bool SettingsChanged_ = false;
- // -- libuv loop
- StageT Stage_ = StageT::SETTINGS_READ;
- bool Error_ = false;
- bool Generate_ = false;
bool BuildFileChanged_ = false;
};
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 55204d708..2064275e7 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -3,6 +3,7 @@
#include "cmRST.h"
#include "cmAlgorithms.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
@@ -32,7 +33,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
, TocTreeDirective("^.. toctree::[ \t]*(.*)$")
, ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
, NoteDirective("^.. note::[ \t]*(.*)$")
- , ModuleRST("^#\\[(=*)\\[\\.rst:$")
+ , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
, CMakeRole("(:cmake)?:("
"command|cpack_gen|generator|variable|envvar|module|policy|"
"prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
@@ -456,6 +457,12 @@ void cmRST::UnindentLines(std::vector<std::string>& lines)
size_t trailingEmpty =
std::distance(rit, cmFindNot(cmReverseRange(lines), std::string()));
+ if ((leadingEmpty + trailingEmpty) >= lines.size()) {
+ // All lines are empty. The markup block is empty. Leave only one.
+ lines.resize(1);
+ return;
+ }
+
std::vector<std::string>::iterator contentEnd = cmRotate(
lines.begin(), lines.begin() + leadingEmpty, lines.end() - trailingEmpty);
lines.erase(contentEnd, lines.end());
diff --git a/Source/cmRange.h b/Source/cmRange.h
new file mode 100644
index 000000000..3be5193e7
--- /dev/null
+++ b/Source/cmRange.h
@@ -0,0 +1,239 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmRange_h
+#define cmRange_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+namespace RangeIterators {
+
+template <typename Iter, typename UnaryPredicate>
+class FilterIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = typename std::iterator_traits<Iter>::pointer;
+ using reference = typename std::iterator_traits<Iter>::reference;
+
+ FilterIterator(Iter b, Iter e, UnaryPredicate p)
+ : Cur(std::move(b))
+ , End(std::move(e))
+ , Pred(std::move(p))
+ {
+ this->SatisfyPredicate();
+ }
+
+ FilterIterator& operator++()
+ {
+ ++this->Cur;
+ this->SatisfyPredicate();
+ return *this;
+ }
+
+ FilterIterator& operator--()
+ {
+ do {
+ --this->Cur;
+ } while (!this->Pred(*this->Cur));
+ return *this;
+ }
+
+ bool operator==(FilterIterator const& other) const
+ {
+ return this->Cur == other.Cur;
+ }
+
+ bool operator!=(FilterIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const -> decltype(*std::declval<Iter>())
+ {
+ return *this->Cur;
+ }
+
+private:
+ void SatisfyPredicate()
+ {
+ while (this->Cur != this->End && !this->Pred(*this->Cur)) {
+ ++this->Cur;
+ }
+ }
+
+ Iter Cur;
+ Iter End;
+ UnaryPredicate Pred;
+};
+
+template <typename Iter, typename UnaryFunction>
+class TransformIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type =
+ typename std::remove_cv<typename std::remove_reference<decltype(
+ std::declval<UnaryFunction>()(*std::declval<Iter>()))>::type>::type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = value_type const*;
+ using reference = value_type const&;
+
+ TransformIterator(Iter i, UnaryFunction f)
+ : Base(std::move(i))
+ , Func(std::move(f))
+ {
+ }
+
+ TransformIterator& operator++()
+ {
+ ++this->Base;
+ return *this;
+ }
+
+ TransformIterator& operator--()
+ {
+ --this->Base;
+ return *this;
+ }
+
+ bool operator==(TransformIterator const& other) const
+ {
+ return this->Base == other.Base;
+ }
+
+ bool operator!=(TransformIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const
+ -> decltype(std::declval<UnaryFunction>()(*std::declval<Iter>()))
+ {
+ return this->Func(*this->Base);
+ }
+
+private:
+ Iter Base;
+ UnaryFunction Func;
+};
+
+} // namespace RangeIterators
+
+template <typename Iter>
+class cmRange
+{
+public:
+ using const_iterator = Iter;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+
+ cmRange(Iter b, Iter e)
+ : Begin(std::move(b))
+ , End(std::move(e))
+ {
+ }
+
+ Iter begin() const { return this->Begin; }
+ Iter end() const { return this->End; }
+ bool empty() const { return this->Begin == this->End; }
+
+ difference_type size() const
+ {
+ return std::distance(this->Begin, this->End);
+ }
+
+ cmRange& advance(difference_type amount) &
+ {
+ std::advance(this->Begin, amount);
+ return *this;
+ }
+
+ cmRange advance(difference_type amount) &&
+ {
+ std::advance(this->Begin, amount);
+ return std::move(*this);
+ }
+
+ cmRange& retreat(difference_type amount) &
+ {
+ std::advance(this->End, -amount);
+ return *this;
+ }
+
+ cmRange retreat(difference_type amount) &&
+ {
+ std::advance(this->End, -amount);
+ return std::move(*this);
+ }
+
+ template <typename UnaryPredicate>
+ bool all_of(UnaryPredicate p) const
+ {
+ return std::all_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool any_of(UnaryPredicate p) const
+ {
+ return std::any_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool none_of(UnaryPredicate p) const
+ {
+ return std::none_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ auto filter(UnaryPredicate p) const
+ -> cmRange<RangeIterators::FilterIterator<Iter, UnaryPredicate>>
+ {
+ using It = RangeIterators::FilterIterator<Iter, UnaryPredicate>;
+ return { It(this->Begin, this->End, p), It(this->End, this->End, p) };
+ }
+
+ template <typename UnaryFunction>
+ auto transform(UnaryFunction f) const
+ -> cmRange<RangeIterators::TransformIterator<Iter, UnaryFunction>>
+ {
+ using It = RangeIterators::TransformIterator<Iter, UnaryFunction>;
+ return { It(this->Begin, f), It(this->End, f) };
+ }
+
+private:
+ Iter Begin;
+ Iter End;
+};
+
+template <typename Iter1, typename Iter2>
+bool operator==(cmRange<Iter1> const& left, cmRange<Iter2> const& right)
+{
+ return left.size() == right.size() &&
+ std::equal(left.begin(), left.end(), right.begin());
+}
+
+template <typename Iter1, typename Iter2>
+auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange<Iter1>
+{
+ return { begin, end };
+}
+
+template <typename Range>
+auto cmMakeRange(Range const& range) -> cmRange<decltype(range.begin())>
+{
+ return { range.begin(), range.end() };
+}
+
+template <typename Range>
+auto cmReverseRange(Range const& range) -> cmRange<decltype(range.rbegin())>
+{
+ return { range.rbegin(), range.rend() };
+}
+
+#endif
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
index bb14e687d..a64ad8c7d 100644
--- a/Source/cmRemoveCommand.cxx
+++ b/Source/cmRemoveCommand.cxx
@@ -25,15 +25,13 @@ bool cmRemoveCommand::InitialPass(std::vector<std::string> const& args,
}
// expand the variable
- std::vector<std::string> varArgsExpanded;
- cmSystemTools::ExpandListArgument(cacheValue, varArgsExpanded);
+ std::vector<std::string> const varArgsExpanded =
+ cmSystemTools::ExpandedListArgument(cacheValue);
// expand the args
// check for REMOVE(VAR v1 v2 ... vn)
- std::vector<std::string> argsExpanded;
- std::vector<std::string> temp;
- temp.insert(temp.end(), args.begin() + 1, args.end());
- cmSystemTools::ExpandList(temp, argsExpanded);
+ std::vector<std::string> const argsExpanded =
+ cmSystemTools::ExpandedLists(args.begin() + 1, args.end());
// now create the new value
std::string value;
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index e347a2cf5..33389cad5 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -91,6 +91,31 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
if (replaceValues.Includes && variable == "INCLUDES") {
return replaceValues.Includes;
}
+ if (replaceValues.SwiftLibraryName) {
+ if (variable == "SWIFT_LIBRARY_NAME") {
+ return replaceValues.SwiftLibraryName;
+ }
+ }
+ if (replaceValues.SwiftModule) {
+ if (variable == "SWIFT_MODULE") {
+ return replaceValues.SwiftModule;
+ }
+ }
+ if (replaceValues.SwiftModuleName) {
+ if (variable == "SWIFT_MODULE_NAME") {
+ return replaceValues.SwiftModuleName;
+ }
+ }
+ if (replaceValues.SwiftOutputFileMap) {
+ if (variable == "SWIFT_OUTPUT_FILE_MAP") {
+ return replaceValues.SwiftOutputFileMap;
+ }
+ }
+ if (replaceValues.SwiftSources) {
+ if (variable == "SWIFT_SOURCES") {
+ return replaceValues.SwiftSources;
+ }
+ }
if (replaceValues.TargetPDB) {
if (variable == "TARGET_PDB") {
return replaceValues.TargetPDB;
@@ -162,16 +187,6 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
}
}
}
- if (replaceValues.SwiftAuxiliarySources) {
- if (variable == "SWIFT_AUXILIARY_SOURCES") {
- return replaceValues.SwiftAuxiliarySources;
- }
- }
- if (replaceValues.SwiftModuleName) {
- if (variable == "SWIFT_MODULE_NAME") {
- return replaceValues.SwiftModuleName;
- }
- }
if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
variable == "TARGET_INSTALLNAME_DIR") {
// All these variables depend on TargetSOName
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 5c0363729..8f361967b 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -58,8 +58,11 @@ public:
const char* Includes;
const char* DependencyFile;
const char* FilterPrefix;
- const char* SwiftAuxiliarySources;
+ const char* SwiftLibraryName;
+ const char* SwiftModule;
const char* SwiftModuleName;
+ const char* SwiftOutputFileMap;
+ const char* SwiftSources;
};
// Expand rule variables in CMake of the type found in language rules
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index 0f51e0eb6..f98984ed6 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -144,7 +144,7 @@ void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
// this will get incorrectly considered a network
// path on windows and cause huge delays.
std::string p = inPath;
- if (!p.empty() && *p.rbegin() != '/') {
+ if (!p.empty() && p.back() != '/') {
p += "/";
}
@@ -176,7 +176,7 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
for (std::string const& path : paths) {
std::string dir = path;
- if (!subdir.empty() && !dir.empty() && *dir.rbegin() != '/') {
+ if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
dir += "/";
}
if (subdir == "include" || subdir == "lib") {
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index e740c0519..1903fd917 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -97,13 +97,13 @@ void cmServer::ProcessRequest(cmConnection* connection,
}
cmSystemTools::SetMessageCallback(
- [&request](const char* msg, const char* title) {
+ [&request](const std::string& msg, const char* title) {
reportMessage(msg, title, request);
});
if (this->Protocol) {
this->Protocol->CMakeInstance()->SetProgressCallback(
- [&request](const char* msg, float prog) {
+ [&request](const std::string& msg, float prog) {
reportProgress(msg, prog, request);
});
this->WriteResponse(connection, this->Protocol->Process(request),
@@ -155,7 +155,7 @@ void cmServer::PrintHello(cmConnection* connection) const
this->WriteJsonObject(connection, hello, nullptr);
}
-void cmServer::reportProgress(const char* msg, float progress,
+void cmServer::reportProgress(const std::string& msg, float progress,
const cmServerRequest& request)
{
if (progress < 0.0f || progress > 1.0f) {
@@ -165,15 +165,14 @@ void cmServer::reportProgress(const char* msg, float progress,
}
}
-void cmServer::reportMessage(const char* msg, const char* title,
+void cmServer::reportMessage(const std::string& msg, const char* title,
const cmServerRequest& request)
{
- assert(msg);
std::string titleString;
if (title) {
titleString = title;
}
- request.ReportMessage(std::string(msg), titleString);
+ request.ReportMessage(msg, titleString);
}
cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
diff --git a/Source/cmServer.h b/Source/cmServer.h
index e1ed27a0c..aba4924c9 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -119,9 +119,9 @@ public:
void OnConnected(cmConnection* connection) override;
private:
- static void reportProgress(const char* msg, float progress,
+ static void reportProgress(const std::string& msg, float progress,
const cmServerRequest& request);
- static void reportMessage(const char* msg, const char* title,
+ static void reportMessage(const std::string& msg, const char* title,
const cmServerRequest& request);
// Handle requests:
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 844a85890..a878890da 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -29,7 +29,7 @@ cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
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);
+ return { std::move(tty) };
}
case UV_FILE:
if (file_id == 0) {
@@ -43,7 +43,7 @@ cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
pipe.init(*this->Server->GetLoop(), 0,
static_cast<cmEventBasedConnection*>(this));
uv_pipe_open(pipe, file_id);
- return std::move(pipe);
+ return { std::move(pipe) };
}
default:
assert(false && "Unable to determine stream type");
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 203ee93e4..558391f30 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -8,6 +8,7 @@
#include "cmGlobalGenerator.h"
#include "cmJsonObjectDictionary.h"
#include "cmJsonObjects.h"
+#include "cmMessageType.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
#include "cmState.h"
@@ -600,6 +601,10 @@ cmServerResponse cmServerProtocol1::ProcessConfigure(
}
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.");
}
@@ -625,7 +630,7 @@ cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
Json::Value obj = Json::objectValue;
// Capabilities information:
- obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(true);
+ obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson();
obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
obj[kTRACE_KEY] = cm->GetTrace();
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 6bd071cfb..41555e8e3 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -5,6 +5,7 @@
#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 3c4111bc1..e9343c7db 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -8,6 +8,7 @@
#include "cmInstalledFile.h"
#include "cmMakefile.h"
#include "cmProperty.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmSystemTools.h"
@@ -33,25 +34,25 @@ bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
}
// Get the scope on which to set the property.
- std::vector<std::string>::const_iterator arg = args.begin();
+ std::string const& scopeName = args.front();
cmProperty::ScopeType scope;
- if (*arg == "GLOBAL") {
+ if (scopeName == "GLOBAL") {
scope = cmProperty::GLOBAL;
- } else if (*arg == "DIRECTORY") {
+ } else if (scopeName == "DIRECTORY") {
scope = cmProperty::DIRECTORY;
- } else if (*arg == "TARGET") {
+ } else if (scopeName == "TARGET") {
scope = cmProperty::TARGET;
- } else if (*arg == "SOURCE") {
+ } else if (scopeName == "SOURCE") {
scope = cmProperty::SOURCE_FILE;
- } else if (*arg == "TEST") {
+ } else if (scopeName == "TEST") {
scope = cmProperty::TEST;
- } else if (*arg == "CACHE") {
+ } else if (scopeName == "CACHE") {
scope = cmProperty::CACHE;
- } else if (*arg == "INSTALL") {
+ } else if (scopeName == "INSTALL") {
scope = cmProperty::INSTALL;
} else {
std::ostringstream e;
- e << "given invalid scope " << *arg << ". "
+ e << "given invalid scope " << scopeName << ". "
<< "Valid scopes are GLOBAL, DIRECTORY, "
"TARGET, SOURCE, TEST, CACHE, INSTALL.";
this->SetError(e.str());
@@ -68,32 +69,32 @@ bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
};
Doing doing = DoingNames;
const char* sep = "";
- for (++arg; arg != args.end(); ++arg) {
- if (*arg == "PROPERTY") {
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "PROPERTY") {
doing = DoingProperty;
- } else if (*arg == "APPEND") {
+ } else if (arg == "APPEND") {
doing = DoingNone;
this->AppendMode = true;
this->Remove = false;
this->AppendAsString = false;
- } else if (*arg == "APPEND_STRING") {
+ } else if (arg == "APPEND_STRING") {
doing = DoingNone;
this->AppendMode = true;
this->Remove = false;
this->AppendAsString = true;
} else if (doing == DoingNames) {
- this->Names.insert(*arg);
+ this->Names.insert(arg);
} else if (doing == DoingProperty) {
- this->PropertyName = *arg;
+ this->PropertyName = arg;
doing = DoingValues;
} else if (doing == DoingValues) {
this->PropertyValue += sep;
sep = ";";
- this->PropertyValue += *arg;
+ this->PropertyValue += arg;
this->Remove = false;
} else {
std::ostringstream e;
- e << "given invalid argument \"" << *arg << "\".";
+ e << "given invalid argument \"" << arg << "\".";
this->SetError(e.str());
return false;
}
@@ -334,7 +335,7 @@ bool cmSetPropertyCommand::HandleCacheMode()
!cmSystemTools::IsOff(this->PropertyValue)) {
std::ostringstream e;
e << "given non-boolean value \"" << this->PropertyValue
- << "\" for CACHE property \"ADVANCED\". ";
+ << R"(" for CACHE property "ADVANCED". )";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
index 642591337..1dc7e69a3 100644
--- a/Source/cmSetTargetPropertiesCommand.cxx
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -4,6 +4,7 @@
#include <iterator>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmTarget.h"
@@ -30,7 +31,7 @@ bool cmSetTargetPropertiesCommand::InitialPass(
this->SetError("called with incorrect number of arguments.");
return false;
}
- propertyPairs.insert(propertyPairs.end(), j, args.end());
+ cmAppend(propertyPairs, j, args.end());
break;
}
numFiles++;
diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx
index e27c675c6..cc9587ca6 100644
--- a/Source/cmSetTestsPropertiesCommand.cxx
+++ b/Source/cmSetTestsPropertiesCommand.cxx
@@ -4,6 +4,7 @@
#include <iterator>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmTest.h"
@@ -30,7 +31,7 @@ bool cmSetTestsPropertiesCommand::InitialPass(
this->SetError("called with incorrect number of arguments.");
return false;
}
- propertyPairs.insert(propertyPairs.end(), j, args.end());
+ cmAppend(propertyPairs, j, args.end());
break;
}
numFiles++;
diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx
index 01758ee3a..9f041bc5f 100644
--- a/Source/cmSiteNameCommand.cxx
+++ b/Source/cmSiteNameCommand.cxx
@@ -52,9 +52,8 @@ bool cmSiteNameCommand::InitialPass(std::vector<std::string> const& args,
// try to find the hostname for this computer
if (!cmSystemTools::IsOff(hostname_cmd)) {
std::string host;
- cmSystemTools::RunSingleCommand(hostname_cmd.c_str(), &host, nullptr,
- nullptr, nullptr,
- cmSystemTools::OUTPUT_NONE);
+ cmSystemTools::RunSingleCommand(hostname_cmd, &host, nullptr, nullptr,
+ nullptr, cmSystemTools::OUTPUT_NONE);
// got the hostname
if (!host.empty()) {
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index a82a58aa9..edad4c7b5 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -34,6 +34,9 @@ public:
~cmSourceFile();
+ cmSourceFile(const cmSourceFile&) = delete;
+ cmSourceFile& operator=(const cmSourceFile&) = delete;
+
/**
* Get the list of the custom commands for this source file
*/
@@ -41,13 +44,13 @@ public:
cmCustomCommand const* GetCustomCommand() const;
void SetCustomCommand(cmCustomCommand* cc);
- ///! Set/Get a property of this source file
+ //! Set/Get a property of this source file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
@@ -55,7 +58,7 @@ public:
command like get_property or get_source_file_property. */
const char* GetPropertyForUser(const std::string& prop);
- ///! Checks is the GENERATED property is set and true
+ //! Checks is the GENERATED property is set and true
/// @return Equivalent to GetPropertyAsBool("GENERATED")
bool GetIsGenerated() const { return this->IsGenerated; }
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index 34ded3890..5cdacaaf8 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -77,9 +77,13 @@ std::vector<std::string> prepareFilesPathsForTree(
const std::string& currentSourceDir)
{
std::vector<std::string> prepared;
+ prepared.reserve(filesPaths.size());
for (auto const& filePath : filesPaths) {
- prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ // If provided file path is actually not a file, silently ignore it.
+ if (cmSystemTools::FileExists(filePath, /*isFile=*/true)) {
+ prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ }
}
return prepared;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index a08e9b8ba..fa7df0b2c 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -556,9 +556,28 @@ const char* cmState::GetGlobalProperty(const std::string& prop)
if (prop == "CMAKE_C_KNOWN_FEATURES") {
return &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1];
}
+ if (prop == "CMAKE_C90_KNOWN_FEATURES") {
+ return &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_C99_KNOWN_FEATURES") {
+ return &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_C11_KNOWN_FEATURES") {
+ return &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
return &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1];
}
+ if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+
#undef STRING_LIST_ELEMENT
return this->GlobalProperties.GetPropertyValue(prop);
}
diff --git a/Source/cmState.h b/Source/cmState.h
index f755f8362..6abe71c0b 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -35,6 +35,9 @@ public:
cmState();
~cmState();
+ cmState(const cmState&) = delete;
+ cmState& operator=(const cmState&) = delete;
+
enum Mode
{
Unknown,
@@ -104,7 +107,7 @@ public:
void RemoveCacheEntryProperty(std::string const& key,
std::string const& propertyName);
- ///! Break up a line like VAR:type="value" into var, type and value
+ //! Break up a line like VAR:type="value" into var, type and value
static bool ParseCacheEntry(const std::string& entry, std::string& var,
std::string& value,
cmStateEnums::CacheEntryType& type);
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 6752743a1..182d3fe73 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -8,8 +8,10 @@
#include <iterator>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStatePrivate.h"
#include "cmStateTypes.h"
@@ -40,9 +42,8 @@ void cmStateDirectory::ComputeRelativePathTopSource()
std::string result = snapshots.front().GetDirectory().GetCurrentSource();
- for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
- it != snapshots.end(); ++it) {
- std::string currentSource = it->GetDirectory().GetCurrentSource();
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentSource = snp.GetDirectory().GetCurrentSource();
if (cmSystemTools::IsSubDirectory(result, currentSource)) {
result = currentSource;
}
@@ -66,9 +67,8 @@ void cmStateDirectory::ComputeRelativePathTopBinary()
std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
- for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
- it != snapshots.end(); ++it) {
- std::string currentBinary = it->GetDirectory().GetCurrentBinary();
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentBinary = snp.GetDirectory().GetCurrentBinary();
if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
result = currentBinary;
}
@@ -621,9 +621,7 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
}
if (prop == "VARIABLES") {
std::vector<std::string> res = this->Snapshot_.ClosureKeys();
- std::vector<std::string> cacheKeys =
- this->Snapshot_.State->GetCacheEntryKeys();
- res.insert(res.end(), cacheKeys.begin(), cacheKeys.end());
+ cmAppend(res, this->Snapshot_.State->GetCacheEntryKeys());
std::sort(res.begin(), res.end());
output = cmJoin(res, ";");
return output.c_str();
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 91d619020..998f90415 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -1,9 +1,13 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#define _SCL_SECURE_NO_WARNINGS
+
#include "cmStringCommand.h"
#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
#include <ctype.h>
+#include <iterator>
#include <memory> // IWYU pragma: keep
#include <sstream>
#include <stdio.h>
@@ -13,6 +17,8 @@
#include "cmCryptoHash.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
@@ -78,6 +84,9 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "STRIP") {
return this->HandleStripCommand(args);
}
+ if (subCommand == "REPEAT") {
+ return this->HandleRepeatCommand(args);
+ }
if (subCommand == "RANDOM") {
return this->HandleRandomCommand(args);
}
@@ -708,6 +717,59 @@ bool cmStringCommand::HandleStripCommand(std::vector<std::string> const& args)
return true;
}
+bool cmStringCommand::HandleRepeatCommand(std::vector<std::string> const& args)
+{
+ // `string(REPEAT "<str>" <times> OUTPUT_VARIABLE)`
+ enum ArgPos : std::size_t
+ {
+ SUB_COMMAND,
+ VALUE,
+ TIMES,
+ OUTPUT_VARIABLE,
+ TOTAL_ARGS
+ };
+
+ if (args.size() != ArgPos::TOTAL_ARGS) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "sub-command REPEAT requires three arguments.");
+ return true;
+ }
+
+ unsigned long times;
+ if (!cmSystemTools::StringToULong(args[ArgPos::TIMES].c_str(), &times)) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "repeat count is not a positive number.");
+ return true;
+ }
+
+ const auto& stringValue = args[ArgPos::VALUE];
+ const auto& variableName = args[ArgPos::OUTPUT_VARIABLE];
+ const auto inStringLength = stringValue.size();
+
+ std::string result;
+ switch (inStringLength) {
+ case 0u:
+ // Nothing to do for zero length input strings
+ break;
+ case 1u:
+ // NOTE If the string to repeat consists of the only character,
+ // use the appropriate constructor.
+ result = std::string(times, stringValue[0]);
+ break;
+ default:
+ result = std::string(inStringLength * times, char{});
+ for (auto i = 0u; i < times; ++i) {
+ std::copy(cm::cbegin(stringValue), cm::cend(stringValue),
+ &result[i * inStringLength]);
+ }
+ break;
+ }
+
+ this->Makefile->AddDefinition(variableName, result.c_str());
+ return true;
+}
+
bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
{
if (args.size() < 2 || args.size() == 3 || args.size() == 5) {
@@ -771,7 +833,7 @@ bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
}
result.push_back(0);
- this->Makefile->AddDefinition(variableName, &*result.begin());
+ this->Makefile->AddDefinition(variableName, result.data());
return true;
}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index cbff73e99..acde60549 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -51,6 +51,7 @@ protected:
bool HandleConcatCommand(std::vector<std::string> const& args);
bool HandleJoinCommand(std::vector<std::string> const& args);
bool HandleStripCommand(std::vector<std::string> const& args);
+ bool HandleRepeatCommand(std::vector<std::string> const& args);
bool HandleRandomCommand(std::vector<std::string> const& args);
bool HandleFindCommand(std::vector<std::string> const& args);
bool HandleTimestampCommand(std::vector<std::string> const& args);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 1d20e2f1a..15014811e 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -5,7 +5,7 @@
#include "cmAlgorithms.h"
#include "cmDuration.h"
#include "cmProcessOutput.h"
-#include "cm_sys_stat.h"
+#include "cmRange.h"
#include "cm_uv.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -42,6 +42,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
@@ -55,12 +56,9 @@
# include <windows.h>
// include wincrypt.h after windows.h
# include <wincrypt.h>
-
-# include <fcntl.h> /* _O_TEXT */
#else
# include <sys/time.h>
# include <unistd.h>
-# include <utime.h>
#endif
#if defined(_WIN32) && \
@@ -90,18 +88,6 @@ static bool cm_isspace(char c)
return ((c & 0x80) == 0) && isspace(c);
}
-class cmSystemToolsFileTime
-{
-public:
-#if defined(_WIN32) && !defined(__CYGWIN__)
- FILETIME timeCreation;
- FILETIME timeLastAccess;
- FILETIME timeLastWrite;
-#else
- struct utimbuf timeBuf;
-#endif
-};
-
#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
// For GetEnvironmentVariables
# if defined(_WIN32)
@@ -134,29 +120,6 @@ static int cm_archive_read_open_file(struct archive* a, const char* file,
#endif
#ifdef _WIN32
-class cmSystemToolsWindowsHandle
-{
-public:
- cmSystemToolsWindowsHandle(HANDLE h)
- : handle_(h)
- {
- }
- ~cmSystemToolsWindowsHandle()
- {
- if (this->handle_ != INVALID_HANDLE_VALUE) {
- CloseHandle(this->handle_);
- }
- }
- explicit operator bool() const
- {
- return this->handle_ != INVALID_HANDLE_VALUE;
- }
- bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; }
- operator HANDLE() const { return this->handle_; }
-
-private:
- HANDLE handle_;
-};
#elif defined(__APPLE__)
# include <crt_externs.h>
@@ -167,7 +130,6 @@ bool cmSystemTools::s_RunCommandHideConsole = false;
bool cmSystemTools::s_DisableRunCommandOutput = false;
bool cmSystemTools::s_ErrorOccured = false;
bool cmSystemTools::s_FatalErrorOccured = false;
-bool cmSystemTools::s_DisableMessages = false;
bool cmSystemTools::s_ForceUnixPaths = false;
// replace replace with with as many times as it shows up in source.
@@ -250,26 +212,6 @@ std::string cmSystemTools::TrimWhitespace(const std::string& s)
return std::string(start, stop + 1);
}
-void cmSystemTools::Error(const char* m1, const char* m2, const char* m3,
- const char* m4)
-{
- std::string message = "CMake Error: ";
- if (m1) {
- message += m1;
- }
- if (m2) {
- message += m2;
- }
- if (m3) {
- message += m3;
- }
- if (m4) {
- message += m4;
- }
- cmSystemTools::s_ErrorOccured = true;
- cmSystemTools::Message(message, "Error");
-}
-
void cmSystemTools::Error(const std::string& m)
{
std::string message = "CMake Error: " + m;
@@ -323,16 +265,13 @@ void cmSystemTools::Stdout(const std::string& s)
}
}
-void cmSystemTools::Message(const char* m1, const char* title)
+void cmSystemTools::Message(const std::string& m, const char* title)
{
- if (s_DisableMessages) {
- return;
- }
if (s_MessageCallback) {
- s_MessageCallback(m1, title);
- return;
+ s_MessageCallback(m, title);
+ } else {
+ std::cerr << m << std::endl;
}
- std::cerr << m1 << std::endl << std::flush;
}
void cmSystemTools::ReportLastSystemError(const char* msg)
@@ -521,6 +460,8 @@ public:
}
free(this->ArgV);
}
+ cmSystemToolsArgV(const cmSystemToolsArgV&) = delete;
+ cmSystemToolsArgV& operator=(const cmSystemToolsArgV&) = delete;
void Store(std::vector<std::string>& args) const
{
for (char** arg = this->ArgV; arg && *arg; ++arg) {
@@ -533,7 +474,7 @@ void cmSystemTools::ParseUnixCommandLine(const char* command,
std::vector<std::string>& args)
{
// Invoke the underlying parser.
- cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+ cmSystemToolsArgV argv(cmsysSystem_Parse_CommandForUnix(command, 0));
argv.Store(args);
}
@@ -542,8 +483,7 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
std::vector<std::string>::const_iterator argEnd)
{
std::vector<std::string> arg_full;
- for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
- std::string const& arg = *a;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
if (cmHasLiteralPrefix(arg, "@")) {
cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
if (!responseFile) {
@@ -561,7 +501,7 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
#else
cmSystemTools::ParseUnixCommandLine(line.c_str(), args2);
#endif
- arg_full.insert(arg_full.end(), args2.begin(), args2.end());
+ cmAppend(arg_full, args2);
}
} else {
arg_full.push_back(arg);
@@ -570,13 +510,14 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
return arg_full;
}
-std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
+std::vector<std::string> cmSystemTools::ParseArguments(const std::string& cmd)
{
std::vector<std::string> args;
std::string arg;
bool win_path = false;
+ const char* command = cmd.c_str();
if (command[0] && command[1] &&
((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
(command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
@@ -740,7 +681,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
argv.push_back(nullptr);
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -785,7 +726,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
cmSystemTools::Stdout(strdata);
}
if (captureStdOut) {
- tempStdOut.insert(tempStdOut.end(), data, data + length);
+ cmAppend(tempStdOut, data, data + length);
}
} else if (pipe == cmsysProcess_Pipe_STDERR) {
if (outputflag != OUTPUT_NONE) {
@@ -793,7 +734,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
cmSystemTools::Stderr(strdata);
}
if (captureStdErr) {
- tempStdErr.insert(tempStdErr.end(), data, data + length);
+ cmAppend(tempStdErr, data, data + length);
}
}
}
@@ -867,7 +808,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
return result;
}
-bool cmSystemTools::RunSingleCommand(const char* command,
+bool cmSystemTools::RunSingleCommand(const std::string& command,
std::string* captureStdOut,
std::string* captureStdErr, int* retVal,
const char* dir, OutputOption outputflag,
@@ -897,7 +838,7 @@ std::string cmSystemTools::PrintSingleCommand(
}
bool cmSystemTools::DoesFileExistWithExtensions(
- const char* name, const std::vector<std::string>& headerExts)
+ const std::string& name, const std::vector<std::string>& headerExts)
{
std::string hname;
@@ -912,9 +853,9 @@ bool cmSystemTools::DoesFileExistWithExtensions(
return false;
}
-std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
- const char* directory,
- const char* toplevel)
+std::string cmSystemTools::FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel)
{
std::string file = fname;
cmSystemTools::ConvertToUnixSlashes(file);
@@ -926,7 +867,7 @@ std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
if (cmSystemTools::FileExists(path)) {
return path;
}
- if (dir.size() < strlen(toplevel)) {
+ if (dir.size() < toplevel.size()) {
break;
}
prevDir = dir;
@@ -935,12 +876,6 @@ std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
return "";
}
-bool cmSystemTools::cmCopyFile(const std::string& source,
- const std::string& destination)
-{
- return Superclass::CopyFileAlways(source, destination);
-}
-
#ifdef _WIN32
cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
{
@@ -1216,17 +1151,8 @@ void cmSystemTools::GlobDirs(const std::string& path,
}
}
-void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
- std::vector<std::string>& newargs)
-{
- std::vector<std::string>::const_iterator i;
- for (i = arguments.begin(); i != arguments.end(); ++i) {
- cmSystemTools::ExpandListArgument(*i, newargs);
- }
-}
-
void cmSystemTools::ExpandListArgument(const std::string& arg,
- std::vector<std::string>& newargs,
+ std::vector<std::string>& argsOut,
bool emptyArgs)
{
// If argument is empty, it is an empty list.
@@ -1235,7 +1161,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
}
// if there are no ; in the name then just copy the current string
if (arg.find(';') == std::string::npos) {
- newargs.push_back(arg);
+ argsOut.push_back(arg);
return;
}
std::string newArg;
@@ -1269,7 +1195,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
last = c + 1;
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
newArg.clear();
}
}
@@ -1282,10 +1208,18 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
newArg.append(last);
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
}
}
+std::vector<std::string> cmSystemTools::ExpandedListArgument(
+ const std::string& arg, bool emptyArgs)
+{
+ std::vector<std::string> argsOut;
+ ExpandListArgument(arg, argsOut, emptyArgs);
+ return argsOut;
+}
+
bool cmSystemTools::SimpleGlob(const std::string& glob,
std::vector<std::string>& files,
int type /* = 0 */)
@@ -1389,14 +1323,6 @@ cmSystemTools::FileFormat cmSystemTools::GetFileFormat(std::string const& ext)
return cmSystemTools::UNKNOWN_FILE_FORMAT;
}
-bool cmSystemTools::Split(const char* s, std::vector<std::string>& l)
-{
- std::vector<std::string> temp;
- bool res = Superclass::Split(s, temp);
- l.insert(l.end(), temp.begin(), temp.end());
- return res;
-}
-
std::string cmSystemTools::ConvertToOutputPath(std::string const& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1424,7 +1350,7 @@ void cmSystemTools::ConvertToOutputSlashes(std::string& path)
#endif
}
-std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
+std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
return cmSystemTools::ConvertToWindowsOutputPath(path);
@@ -1438,12 +1364,12 @@ std::string cmSystemTools::RelativePath(std::string const& local,
std::string const& remote)
{
if (!cmSystemTools::FileIsFullPath(local)) {
- cmSystemTools::Error("RelativePath must be passed a full path to local: ",
- local.c_str());
+ cmSystemTools::Error("RelativePath must be passed a full path to local: " +
+ local);
}
if (!cmSystemTools::FileIsFullPath(remote)) {
- cmSystemTools::Error("RelativePath must be passed a full path to remote: ",
- remote.c_str());
+ cmSystemTools::Error(
+ "RelativePath must be passed a full path to remote: " + remote);
}
return cmsys::SystemTools::RelativePath(local, remote);
}
@@ -1522,36 +1448,6 @@ std::string cmSystemTools::ForceToRelativePath(std::string const& local_path,
return relative;
}
-std::string cmSystemTools::CollapseCombinedPath(std::string const& dir,
- std::string const& file)
-{
- if (dir.empty() || dir == ".") {
- return file;
- }
-
- std::vector<std::string> dirComponents;
- std::vector<std::string> fileComponents;
- cmSystemTools::SplitPath(dir, dirComponents);
- cmSystemTools::SplitPath(file, fileComponents);
-
- if (fileComponents.empty()) {
- return dir;
- }
- if (!fileComponents[0].empty()) {
- // File is not a relative path.
- return file;
- }
-
- std::vector<std::string>::iterator i = fileComponents.begin() + 1;
- while (i != fileComponents.end() && *i == ".." && dirComponents.size() > 1) {
- ++i; // Remove ".." file component.
- dirComponents.pop_back(); // Remove last dir component.
- }
-
- dirComponents.insert(dirComponents.end(), i, fileComponents.end());
- return cmSystemTools::JoinPath(dirComponents);
-}
-
#ifdef CMAKE_BUILD_WITH_CMAKE
bool cmSystemTools::UnsetEnv(const char* value)
{
@@ -1627,13 +1523,13 @@ void cmSystemTools::EnableVSConsoleOutput()
#endif
}
-bool cmSystemTools::IsPathToFramework(const char* path)
+bool cmSystemTools::IsPathToFramework(const std::string& path)
{
return (cmSystemTools::FileIsFullPath(path) &&
cmHasLiteralSuffix(path, ".framework"));
}
-bool cmSystemTools::CreateTar(const char* outFileName,
+bool cmSystemTools::CreateTar(const std::string& outFileName,
const std::vector<std::string>& files,
cmTarCompression compressType, bool verbose,
std::string const& mtime,
@@ -1641,7 +1537,7 @@ bool cmSystemTools::CreateTar(const char* outFileName,
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- cmsys::ofstream fout(outFileName, std::ios::out | std::ios::binary);
+ cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
if (!fout) {
std::string e = "Cannot open output file \"";
e += outFileName;
@@ -1661,6 +1557,9 @@ bool cmSystemTools::CreateTar(const char* outFileName,
case TarCompressXZ:
compress = cmArchiveWrite::CompressXZ;
break;
+ case TarCompressZstd:
+ compress = cmArchiveWrite::CompressZstd;
+ break;
case TarCompressNone:
compress = cmArchiveWrite::CompressNone;
break;
@@ -1670,20 +1569,18 @@ bool cmSystemTools::CreateTar(const char* outFileName,
a.SetMTime(mtime);
a.SetVerbose(verbose);
+ bool tarCreatedSuccessfully = true;
for (auto path : files) {
if (cmSystemTools::FileIsFullPath(path)) {
// Get the relative path to the file.
path = cmSystemTools::RelativePath(cwd, path);
}
if (!a.Add(path)) {
- break;
+ cmSystemTools::Error(a.GetError());
+ tarCreatedSuccessfully = false;
}
}
- if (!a) {
- cmSystemTools::Error(a.GetError());
- return false;
- }
- return true;
+ return tarCreatedSuccessfully;
#else
(void)outFileName;
(void)files;
@@ -1795,6 +1692,16 @@ void list_item_verbose(FILE* out, struct archive_entry* entry)
fflush(out);
}
+void ArchiveError(const char* m1, struct archive* a)
+{
+ std::string message(m1);
+ const char* m2 = archive_error_string(a);
+ if (m2) {
+ message += m2;
+ }
+ cmSystemTools::Error(message);
+}
+
bool la_diagnostic(struct archive* ar, __LA_SSIZE_T r)
{
// See archive.h definition of ARCHIVE_OK for return values.
@@ -1853,7 +1760,9 @@ bool copy_data(struct archive* ar, struct archive* aw)
# endif
}
-bool extract_tar(const char* outFileName, bool verbose, bool extract)
+bool extract_tar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose,
+ bool extract)
{
cmLocaleRAII localeRAII;
static_cast<void>(localeRAII);
@@ -1862,10 +1771,24 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
struct archive_entry* entry;
- int r = cm_archive_read_open_file(a, outFileName, 10240);
+
+ struct archive* matching = archive_match_new();
+ if (matching == nullptr) {
+ cmSystemTools::Error("Out of memory");
+ return false;
+ }
+
+ for (const auto& filename : files) {
+ if (archive_match_include_pattern(matching, filename.c_str()) !=
+ ARCHIVE_OK) {
+ cmSystemTools::Error("Failed to add to inclusion list: " + filename);
+ return false;
+ }
+ }
+
+ int r = cm_archive_read_open_file(a, outFileName.c_str(), 10240);
if (r) {
- cmSystemTools::Error("Problem with archive_read_open_file(): ",
- archive_error_string(a));
+ ArchiveError("Problem with archive_read_open_file(): ", a);
archive_write_free(ext);
archive_read_close(a);
return false;
@@ -1876,10 +1799,14 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
break;
}
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_read_next_header(): ",
- archive_error_string(a));
+ ArchiveError("Problem with archive_read_next_header(): ", a);
break;
}
+
+ if (archive_match_excluded(matching, entry)) {
+ continue;
+ }
+
if (verbose) {
if (extract) {
cmSystemTools::Stdout("x ");
@@ -1895,8 +1822,7 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
if (extract) {
r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_write_disk_set_options(): ",
- archive_error_string(ext));
+ ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
break;
}
@@ -1907,8 +1833,7 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
r = archive_write_finish_entry(ext);
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_write_finish_entry(): ",
- archive_error_string(ext));
+ ArchiveError("Problem with archive_write_finish_entry(): ", ext);
break;
}
}
@@ -1920,14 +1845,34 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
# endif
else {
- cmSystemTools::Error("Problem with archive_write_header(): ",
- archive_error_string(ext));
- cmSystemTools::Error("Current file: ",
- cm_archive_entry_pathname(entry).c_str());
+ ArchiveError("Problem with archive_write_header(): ", ext);
+ cmSystemTools::Error("Current file: " +
+ cm_archive_entry_pathname(entry));
break;
}
}
}
+
+ bool error_occured = false;
+ if (matching != nullptr) {
+ const char* p;
+ int ar;
+
+ while ((ar = archive_match_path_unmatched_inclusions_next(matching, &p)) ==
+ ARCHIVE_OK) {
+ cmSystemTools::Error("tar: " + std::string(p) +
+ ": Not found in archive");
+ error_occured = true;
+ }
+ if (error_occured) {
+ return false;
+ }
+ if (ar == ARCHIVE_FATAL) {
+ cmSystemTools::Error("tar: Out of memory");
+ return false;
+ }
+ }
+ archive_match_free(matching);
archive_write_free(ext);
archive_read_close(a);
archive_read_free(a);
@@ -1936,23 +1881,29 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
#endif
-bool cmSystemTools::ExtractTar(const char* outFileName, bool verbose)
+bool cmSystemTools::ExtractTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
- return extract_tar(outFileName, verbose, true);
+ return extract_tar(outFileName, files, verbose, true);
#else
(void)outFileName;
+ (void)files;
(void)verbose;
return false;
#endif
}
-bool cmSystemTools::ListTar(const char* outFileName, bool verbose)
+bool cmSystemTools::ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
- return extract_tar(outFileName, verbose, false);
+ return extract_tar(outFileName, files, verbose, false);
#else
(void)outFileName;
+ (void)files;
(void)verbose;
return false;
#endif
@@ -2018,26 +1969,26 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
processOutput.DecodeText(data, length, strdata, 1);
// Append to the stdout buffer.
std::vector<char>::size_type size = out.size();
- out.insert(out.end(), strdata.begin(), strdata.end());
+ cmAppend(out, strdata);
outiter = out.begin() + size;
} else if (pipe == cmsysProcess_Pipe_STDERR) {
processOutput.DecodeText(data, length, strdata, 2);
// Append to the stderr buffer.
std::vector<char>::size_type size = err.size();
- err.insert(err.end(), strdata.begin(), strdata.end());
+ cmAppend(err, strdata);
erriter = err.begin() + size;
} else if (pipe == cmsysProcess_Pipe_None) {
// Both stdout and stderr pipes have broken. Return leftover data.
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
std::vector<char>::size_type size = out.size();
- out.insert(out.end(), strdata.begin(), strdata.end());
+ cmAppend(out, strdata);
outiter = out.begin() + size;
}
processOutput.DecodeText(std::string(), strdata, 2);
if (!strdata.empty()) {
std::vector<char>::size_type size = err.size();
- err.insert(err.end(), strdata.begin(), strdata.end());
+ cmAppend(err, strdata);
erriter = err.begin() + size;
}
if (!out.empty()) {
@@ -2055,6 +2006,71 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
}
}
+#ifdef _WIN32
+static void EnsureStdPipe(DWORD fd)
+{
+ if (GetStdHandle(fd) != INVALID_HANDLE_VALUE) {
+ return;
+ }
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ HANDLE h = CreateFileW(
+ L"NUL",
+ fd == STD_INPUT_HANDLE ? FILE_GENERIC_READ
+ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ std::string msg = std::string(message, size);
+ LocalFree(message);
+ std::cerr << "failed to open NUL for missing stdio pipe: " << msg;
+ abort();
+ }
+
+ SetStdHandle(fd, h);
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STD_INPUT_HANDLE);
+ EnsureStdPipe(STD_OUTPUT_HANDLE);
+ EnsureStdPipe(STD_ERROR_HANDLE);
+}
+#else
+static void EnsureStdPipe(int fd)
+{
+ if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
+ return;
+ }
+
+ int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
+ if (f == -1) {
+ perror("failed to open /dev/null for missing stdio pipe");
+ abort();
+ }
+ if (f != fd) {
+ dup2(f, fd);
+ close(f);
+ }
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STDIN_FILENO);
+ EnsureStdPipe(STDOUT_FILENO);
+ EnsureStdPipe(STDERR_FILENO);
+}
+#endif
+
void cmSystemTools::DoNotInheritStdPipes()
{
#ifdef _WIN32
@@ -2082,88 +2098,6 @@ void cmSystemTools::DoNotInheritStdPipes()
#endif
}
-bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle hFrom = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fromFile).c_str(), GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- cmSystemToolsWindowsHandle hTo = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(toFile).c_str(),
- FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!hFrom || !hTo) {
- return false;
- }
- FILETIME timeCreation;
- FILETIME timeLastAccess;
- FILETIME timeLastWrite;
- if (!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite)) {
- return false;
- }
- return SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite) != 0;
-#else
- struct stat fromStat;
- if (stat(fromFile, &fromStat) < 0) {
- return false;
- }
-
- struct utimbuf buf;
- buf.actime = fromStat.st_atime;
- buf.modtime = fromStat.st_mtime;
- return utime(toFile, &buf) >= 0;
-#endif
-}
-
-cmSystemToolsFileTime* cmSystemTools::FileTimeNew()
-{
- return new cmSystemToolsFileTime;
-}
-
-void cmSystemTools::FileTimeDelete(cmSystemToolsFileTime* t)
-{
- delete t;
-}
-
-bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle h = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fname).c_str(), GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!h) {
- return false;
- }
- if (!GetFileTime(h, &t->timeCreation, &t->timeLastAccess,
- &t->timeLastWrite)) {
- return false;
- }
-#else
- struct stat st;
- if (stat(fname, &st) < 0) {
- return false;
- }
- t->timeBuf.actime = st.st_atime;
- t->timeBuf.modtime = st.st_mtime;
-#endif
- return true;
-}
-
-bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle h = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fname).c_str(),
- FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!h) {
- return false;
- }
- return SetFileTime(h, &t->timeCreation, &t->timeLastAccess,
- &t->timeLastWrite) != 0;
-#else
- return utime(fname, &t->timeBuf) >= 0;
-#endif
-}
-
#ifdef _WIN32
# ifndef CRYPT_SILENT
# define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */
@@ -3015,7 +2949,7 @@ bool cmSystemTools::CheckRPath(std::string const& file,
#endif
}
-bool cmSystemTools::RepeatedRemoveDirectory(const char* dir)
+bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
{
// Windows sometimes locks files temporarily so try a few times.
for (int i = 0; i < 10; ++i) {
@@ -3064,6 +2998,12 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value)
{
errno = 0;
char* endp;
+ while (isspace(*str)) {
+ ++str;
+ }
+ if (*str == '-') {
+ return false;
+ }
*value = strtoul(str, &endp, 10);
return (*endp == '\0') && (endp != str) && (errno == 0);
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 0f92fe257..016c2665f 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -15,8 +15,6 @@
#include <string>
#include <vector>
-class cmSystemToolsFileTime;
-
/** \class cmSystemTools
* \brief A collection of useful functions for CMake.
*
@@ -29,23 +27,56 @@ public:
typedef cmsys::SystemTools Superclass;
typedef cmProcessOutput::Encoding Encoding;
- /** Expand out any arguments in the vector that have ; separated
- * strings into multiple arguments. A new vector is created
- * containing the expanded versions of all arguments in argsIn.
+ /**
+ * Expand the ; separated string @a arg into multiple arguments.
+ * All found arguments are appended to @a argsOut.
*/
- static void ExpandList(std::vector<std::string> const& argsIn,
- std::vector<std::string>& argsOut);
static void ExpandListArgument(const std::string& arg,
std::vector<std::string>& argsOut,
bool emptyArgs = false);
/**
+ * Expand out any arguments in the string range [@a first, @a last) that have
+ * ; separated strings into multiple arguments. All found arguments are
+ * appended to @a argsOut.
+ */
+ template <class InputIt>
+ static void ExpandLists(InputIt first, InputIt last,
+ std::vector<std::string>& argsOut)
+ {
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ }
+
+ /**
+ * Same as ExpandListArgument but a new vector is created containing
+ * the expanded arguments from the string @a arg.
+ */
+ static std::vector<std::string> ExpandedListArgument(const std::string& arg,
+ bool emptyArgs = false);
+
+ /**
+ * Same as ExpandList but a new vector is created containing the expanded
+ * versions of all arguments in the string range [@a first, @a last).
+ */
+ template <class InputIt>
+ static std::vector<std::string> ExpandedLists(InputIt first, InputIt last)
+ {
+ std::vector<std::string> argsOut;
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ return argsOut;
+ }
+
+ /**
* Look for and replace registry values in a string
*/
static void ExpandRegistryValues(std::string& source,
KeyWOW64 view = KeyWOW64_Default);
- ///! Escape quotes in a string.
+ //! Escape quotes in a string.
static std::string EscapeQuotes(const std::string& str);
/** Map help document name to file name. */
@@ -56,7 +87,7 @@ public:
*/
static std::string TrimWhitespace(const std::string& s);
- using MessageCallback = std::function<void(const char*, const char*)>;
+ using MessageCallback = std::function<void(const std::string&, const char*)>;
/**
* Set the function used by GUIs to display error messages
* Function gets passed: message as a const char*,
@@ -67,26 +98,20 @@ public:
/**
* Display an error message.
*/
- static void Error(const char* m, const char* m2 = nullptr,
- const char* m3 = nullptr, const char* m4 = nullptr);
static void Error(const std::string& m);
/**
* Display a message.
*/
- static void Message(const char* m, const char* title = nullptr);
- static void Message(const std::string& m, const char* title = nullptr)
- {
- Message(m.c_str(), title);
- }
+ static void Message(const std::string& m, const char* title = nullptr);
using OutputCallback = std::function<void(std::string const&)>;
- ///! Send a string to stdout
+ //! Send a string to stdout
static void Stdout(const std::string& s);
static void SetStdoutCallback(OutputCallback f);
- ///! Send a string to stderr
+ //! Send a string to stderr
static void Stderr(const std::string& s);
static void SetStderrCallback(OutputCallback f);
@@ -94,25 +119,25 @@ public:
static void SetInterruptCallback(InterruptCallback f);
static bool GetInterruptFlag();
- ///! Return true if there was an error at any point.
+ //! Return true if there was an error at any point.
static bool GetErrorOccuredFlag()
{
return cmSystemTools::s_ErrorOccured ||
cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
}
- ///! If this is set to true, cmake stops processing commands.
+ //! If this is set to true, cmake stops processing commands.
static void SetFatalErrorOccured()
{
cmSystemTools::s_FatalErrorOccured = true;
}
static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
- ///! Return true if there was an error at any point.
+ //! Return true if there was an error at any point.
static bool GetFatalErrorOccured()
{
return cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
}
- ///! Set the error occurred flag and fatal error back to false
+ //! Set the error occurred flag and fatal error back to false
static void ResetErrorOccuredFlag()
{
cmSystemTools::s_FatalErrorOccured = false;
@@ -142,22 +167,22 @@ public:
static bool IsOff(const char* val);
static bool IsOff(const std::string& val);
- ///! Return true if value is NOTFOUND or ends in -NOTFOUND.
+ //! Return true if value is NOTFOUND or ends in -NOTFOUND.
static bool IsNOTFOUND(const char* value);
- ///! Return true if the path is a framework
- static bool IsPathToFramework(const char* value);
+ //! Return true if the path is a framework
+ static bool IsPathToFramework(const std::string& value);
static bool DoesFileExistWithExtensions(
- const char* name, const std::vector<std::string>& sourceExts);
+ const std::string& name, const std::vector<std::string>& sourceExts);
/**
* Check if the given file exists in one of the parent directory of the
* given file or directory and if it does, return the name of the file.
* Toplevel specifies the top-most directory to where it will look.
*/
- static std::string FileExistsInParentDirectories(const char* fname,
- const char* directory,
- const char* toplevel);
+ static std::string FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel);
static void Glob(const std::string& directory, const std::string& regexp,
std::vector<std::string>& files);
@@ -176,23 +201,19 @@ public:
static bool SimpleGlob(const std::string& glob,
std::vector<std::string>& files, int type = 0);
- ///! Copy a file.
- static bool cmCopyFile(const std::string& source,
- const std::string& destination);
-
/** Rename a file or directory within a single disk volume (atomic
if possible). */
static bool RenameFile(const std::string& oldname,
const std::string& newname);
- ///! Compute the hash of a file
+ //! Compute the hash of a file
static std::string ComputeFileHash(const std::string& source,
cmCryptoHash::Algo algo);
/** Compute the md5sum of a string. */
static std::string ComputeStringMD5(const std::string& input);
- ///! Get the SHA thumbprint for a certificate file
+ //! Get the SHA thumbprint for a certificate file
static std::string ComputeCertificateThumbprint(const std::string& source);
/**
@@ -224,7 +245,7 @@ public:
OUTPUT_FORWARD,
OUTPUT_PASSTHROUGH
};
- static bool RunSingleCommand(const char* command,
+ static bool RunSingleCommand(const std::string& command,
std::string* captureStdOut = nullptr,
std::string* captureStdErr = nullptr,
int* retVal = nullptr,
@@ -250,7 +271,7 @@ public:
/**
* Parse arguments out of a single string command
*/
- static std::vector<std::string> ParseArguments(const char* command);
+ static std::vector<std::string> ParseArguments(const std::string& command);
/** Parse arguments out of a windows command line string. */
static void ParseWindowsCommandLine(const char* command,
@@ -274,8 +295,6 @@ public:
static size_t CalculateCommandLineLengthLimit();
- static void EnableMessages() { s_DisableMessages = false; }
- static void DisableMessages() { s_DisableMessages = true; }
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
@@ -351,9 +370,6 @@ public:
cmDuration timeout, std::vector<char>& out,
std::vector<char>& err);
- /** Split a string on its newlines into multiple lines. Returns
- false only if the last line stored had no newline. */
- static bool Split(const char* s, std::vector<std::string>& l);
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
@@ -364,7 +380,7 @@ public:
// ConvertToRunCommandPath does not use s_ForceUnixPaths and should
// be used when RunCommand is called from cmake, because the
// running cmake needs paths to be in its format
- static std::string ConvertToRunCommandPath(const char* path);
+ static std::string ConvertToRunCommandPath(const std::string& path);
/** compute the relative path from local to remote. local must
be a directory. remote can be a file or a directory.
@@ -385,12 +401,6 @@ public:
static std::string ForceToRelativePath(std::string const& local_path,
std::string const& remote_path);
- /** Joins two paths while collapsing x/../ parts
- * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d"
- */
- static std::string CollapseCombinedPath(std::string const& dir,
- std::string const& file);
-
#ifdef CMAKE_BUILD_WITH_CMAKE
/** Remove an environment variable */
static bool UnsetEnv(const char* value);
@@ -423,21 +433,33 @@ public:
/** Setup the environment to enable VS 8 IDE output. */
static void EnableVSConsoleOutput();
+ enum cmTarAction
+ {
+ TarActionCreate,
+ TarActionList,
+ TarActionExtract,
+ TarActionNone
+ };
+
/** Create tar */
enum cmTarCompression
{
TarCompressGZip,
TarCompressBZip2,
TarCompressXZ,
+ TarCompressZstd,
TarCompressNone
};
- static bool ListTar(const char* outFileName, bool verbose);
- static bool CreateTar(const char* outFileName,
+
+ static bool ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose);
+ static bool CreateTar(const std::string& outFileName,
const std::vector<std::string>& files,
cmTarCompression compressType, bool verbose,
std::string const& mtime = std::string(),
std::string const& format = std::string());
- static bool ExtractTar(const char* inFileName, bool verbose);
+ static bool ExtractTar(const std::string& inFileName,
+ const std::vector<std::string>& files, bool verbose);
// This should be called first thing in main
// it will keep child processes from inheriting the
// stdin and stdout of this process. This is important
@@ -445,15 +467,7 @@ public:
// not get stuck waiting for all the output on the pipes.
static void DoNotInheritStdPipes();
- /** Copy the file create/access/modify times from the file named by
- the first argument to that named by the second. */
- static bool CopyFileTime(const char* fromFile, const char* toFile);
-
- /** Save and restore file times. */
- static cmSystemToolsFileTime* FileTimeNew();
- static void FileTimeDelete(cmSystemToolsFileTime*);
- static bool FileTimeGet(const char* fname, cmSystemToolsFileTime* t);
- static bool FileTimeSet(const char* fname, cmSystemToolsFileTime* t);
+ static void EnsureStdPipes();
/** Random seed generation. */
static unsigned int RandomSeed();
@@ -497,7 +511,7 @@ public:
static bool CheckRPath(std::string const& file, std::string const& newRPath);
/** Remove a directory; repeat a few times in case of locked files. */
- static bool RepeatedRemoveDirectory(const char* dir);
+ static bool RepeatedRemoveDirectory(const std::string& dir);
/** Tokenize a string */
static std::vector<std::string> tokenize(const std::string& str,
@@ -546,7 +560,6 @@ private:
static bool s_RunCommandHideConsole;
static bool s_ErrorOccured;
static bool s_FatalErrorOccured;
- static bool s_DisableMessages;
static bool s_DisableRunCommandOutput;
};
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 93cdd46ce..cd675865a 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -5,6 +5,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <assert.h>
+#include <initializer_list>
#include <iterator>
#include <set>
#include <sstream>
@@ -12,6 +13,7 @@
#include <unordered_set>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -20,6 +22,8 @@
#include "cmMessageType.h"
#include "cmMessenger.h"
#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmSourceFileLocationKind.h"
@@ -155,6 +159,26 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>(
class cmTargetInternals
{
public:
+ cmStateEnums::TargetType TargetType;
+ cmMakefile* Makefile;
+ cmPolicies::PolicyMap PolicyMap;
+ std::string Name;
+ std::string InstallPath;
+ std::string RuntimeInstallPath;
+ cmPropertyMap Properties;
+ bool IsGeneratorProvided;
+ bool HaveInstallRule;
+ bool DLLPlatform;
+ bool IsAndroid;
+ bool IsImportedTarget;
+ bool ImportedGloballyVisible;
+ bool BuildInterfaceIncludesAppended;
+ std::set<BT<std::string>> Utilities;
+ std::vector<cmCustomCommand> PreBuildCommands;
+ std::vector<cmCustomCommand> PreLinkCommands;
+ std::vector<cmCustomCommand> PostBuildCommands;
+ std::set<std::string> SystemIncludeDirectories;
+ cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
std::vector<std::string> IncludeDirectoriesEntries;
std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
std::vector<std::string> CompileOptionsEntries;
@@ -171,166 +195,188 @@ public:
std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> LinkImplementationPropertyEntries;
std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+ std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
+ TLLCommands;
+ cmListFileBacktrace Backtrace;
+
+public:
+ bool CheckImportedLibName(std::string const& prop,
+ std::string const& value) const;
+
+ std::string ProcessSourceItemCMP0049(const std::string& s);
};
cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
Visibility vis, cmMakefile* mf)
+ : impl(cm::make_unique<cmTargetInternals>())
{
assert(mf);
- this->IsGeneratorProvided = false;
- this->Name = name;
- this->TargetTypeValue = type;
- this->Makefile = mf;
- this->HaveInstallRule = false;
- this->DLLPlatform = false;
- this->IsAndroid = false;
- this->IsImportedTarget =
+ impl->TargetType = type;
+ impl->Makefile = mf;
+ impl->Name = name;
+ impl->IsGeneratorProvided = false;
+ impl->HaveInstallRule = false;
+ impl->DLLPlatform = false;
+ impl->IsAndroid = false;
+ impl->IsImportedTarget =
(vis == VisibilityImported || vis == VisibilityImportedGlobally);
- this->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
- this->BuildInterfaceIncludesAppended = false;
+ impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
+ impl->BuildInterfaceIncludesAppended = false;
// Check whether this is a DLL platform.
- this->DLLPlatform =
- !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+ impl->DLLPlatform =
+ !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
// Check whether we are targeting an Android platform.
- this->IsAndroid =
- (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+ impl->IsAndroid =
+ (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+
+ std::string gKey;
+ gKey.reserve(128);
+ gKey += "CMAKE_";
+ auto InitProperty = [this, mf, &gKey](const std::string& property,
+ const char* default_value) {
+ // Replace everything after "CMAKE_"
+ gKey.replace(gKey.begin() + 6, gKey.end(), property);
+ if (const char* value = mf->GetDefinition(gKey)) {
+ this->SetProperty(property, value);
+ } else if (default_value) {
+ this->SetProperty(property, default_value);
+ }
+ };
// Setup default property values.
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("ANDROID_API", nullptr);
- this->SetPropertyDefault("ANDROID_API_MIN", nullptr);
- this->SetPropertyDefault("ANDROID_ARCH", nullptr);
- this->SetPropertyDefault("ANDROID_STL_TYPE", nullptr);
- this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", nullptr);
- this->SetPropertyDefault("ANDROID_PROCESS_MAX", nullptr);
- this->SetPropertyDefault("ANDROID_PROGUARD", nullptr);
- this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
- this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", nullptr);
- this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
- this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", nullptr);
- this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", nullptr);
- this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
- this->SetPropertyDefault("BUILD_RPATH", nullptr);
- this->SetPropertyDefault("BUILD_RPATH_USE_ORIGIN", nullptr);
- this->SetPropertyDefault("INSTALL_NAME_DIR", nullptr);
- this->SetPropertyDefault("INSTALL_RPATH", "");
- this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
- this->SetPropertyDefault("INTERPROCEDURAL_OPTIMIZATION", nullptr);
- this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
- this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
- this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("Fortran_FORMAT", nullptr);
- this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", nullptr);
- this->SetPropertyDefault("Fortran_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("GNUtoMS", nullptr);
- this->SetPropertyDefault("OSX_ARCHITECTURES", nullptr);
- this->SetPropertyDefault("IOS_INSTALL_COMBINED", nullptr);
- this->SetPropertyDefault("AUTOMOC", nullptr);
- this->SetPropertyDefault("AUTOUIC", nullptr);
- this->SetPropertyDefault("AUTORCC", nullptr);
- this->SetPropertyDefault("AUTOGEN_ORIGIN_DEPENDS", nullptr);
- this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr);
- this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr);
- this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr);
- this->SetPropertyDefault("AUTOMOC_MACRO_NAMES", nullptr);
- this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", nullptr);
- this->SetPropertyDefault("AUTOUIC_OPTIONS", nullptr);
- this->SetPropertyDefault("AUTOUIC_SEARCH_PATHS", nullptr);
- this->SetPropertyDefault("AUTORCC_OPTIONS", nullptr);
- this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", nullptr);
- this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", nullptr);
- this->SetPropertyDefault("WIN32_EXECUTABLE", nullptr);
- this->SetPropertyDefault("MACOSX_BUNDLE", nullptr);
- this->SetPropertyDefault("MACOSX_RPATH", nullptr);
- this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", nullptr);
- this->SetPropertyDefault("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
- this->SetPropertyDefault("C_CLANG_TIDY", nullptr);
- this->SetPropertyDefault("C_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("C_CPPLINT", nullptr);
- this->SetPropertyDefault("C_CPPCHECK", nullptr);
- this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("LINK_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("C_STANDARD", nullptr);
- this->SetPropertyDefault("C_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("C_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CXX_CLANG_TIDY", nullptr);
- this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("CXX_CPPLINT", nullptr);
- this->SetPropertyDefault("CXX_CPPCHECK", nullptr);
- this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("CXX_STANDARD", nullptr);
- this->SetPropertyDefault("CXX_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("CXX_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CUDA_STANDARD", nullptr);
- this->SetPropertyDefault("CUDA_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("CUDA_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CUDA_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("CUDA_SEPARABLE_COMPILATION", nullptr);
- this->SetPropertyDefault("LINK_SEARCH_START_STATIC", nullptr);
- this->SetPropertyDefault("LINK_SEARCH_END_STATIC", nullptr);
- this->SetPropertyDefault("FOLDER", nullptr);
+ InitProperty("ANDROID_API", nullptr);
+ InitProperty("ANDROID_API_MIN", nullptr);
+ InitProperty("ANDROID_ARCH", nullptr);
+ InitProperty("ANDROID_STL_TYPE", nullptr);
+ InitProperty("ANDROID_SKIP_ANT_STEP", nullptr);
+ InitProperty("ANDROID_PROCESS_MAX", nullptr);
+ InitProperty("ANDROID_PROGUARD", nullptr);
+ InitProperty("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
+ InitProperty("ANDROID_SECURE_PROPS_PATH", nullptr);
+ InitProperty("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
+ InitProperty("ANDROID_JAVA_SOURCE_DIR", nullptr);
+ InitProperty("ANDROID_JAR_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_JAR_DEPENDENCIES", nullptr);
+ InitProperty("ANDROID_ASSETS_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
+ InitProperty("BUILD_RPATH", nullptr);
+ InitProperty("BUILD_RPATH_USE_ORIGIN", nullptr);
+ InitProperty("INSTALL_NAME_DIR", nullptr);
+ InitProperty("INSTALL_RPATH", "");
+ InitProperty("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ InitProperty("INTERPROCEDURAL_OPTIMIZATION", nullptr);
+ InitProperty("SKIP_BUILD_RPATH", "OFF");
+ InitProperty("BUILD_WITH_INSTALL_RPATH", "OFF");
+ InitProperty("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("LIBRARY_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("RUNTIME_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("PDB_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("FRAMEWORK", nullptr);
+ InitProperty("Fortran_FORMAT", nullptr);
+ InitProperty("Fortran_MODULE_DIRECTORY", nullptr);
+ InitProperty("Fortran_COMPILER_LAUNCHER", nullptr);
+ InitProperty("GNUtoMS", nullptr);
+ InitProperty("OSX_ARCHITECTURES", nullptr);
+ InitProperty("IOS_INSTALL_COMBINED", nullptr);
+ InitProperty("AUTOMOC", nullptr);
+ InitProperty("AUTOUIC", nullptr);
+ InitProperty("AUTORCC", nullptr);
+ InitProperty("AUTOGEN_ORIGIN_DEPENDS", nullptr);
+ InitProperty("AUTOGEN_PARALLEL", nullptr);
+ InitProperty("AUTOMOC_COMPILER_PREDEFINES", nullptr);
+ InitProperty("AUTOMOC_DEPEND_FILTERS", nullptr);
+ InitProperty("AUTOMOC_MACRO_NAMES", nullptr);
+ InitProperty("AUTOMOC_MOC_OPTIONS", nullptr);
+ InitProperty("AUTOUIC_OPTIONS", nullptr);
+ InitProperty("AUTOUIC_SEARCH_PATHS", nullptr);
+ InitProperty("AUTORCC_OPTIONS", nullptr);
+ InitProperty("LINK_DEPENDS_NO_SHARED", nullptr);
+ InitProperty("LINK_INTERFACE_LIBRARIES", nullptr);
+ InitProperty("MSVC_RUNTIME_LIBRARY", nullptr);
+ InitProperty("WIN32_EXECUTABLE", nullptr);
+ InitProperty("MACOSX_BUNDLE", nullptr);
+ InitProperty("MACOSX_RPATH", nullptr);
+ InitProperty("NO_SYSTEM_FROM_IMPORTED", nullptr);
+ InitProperty("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
+ InitProperty("C_CLANG_TIDY", nullptr);
+ InitProperty("C_COMPILER_LAUNCHER", nullptr);
+ InitProperty("C_CPPLINT", nullptr);
+ InitProperty("C_CPPCHECK", nullptr);
+ InitProperty("C_INCLUDE_WHAT_YOU_USE", nullptr);
+ InitProperty("LINK_WHAT_YOU_USE", nullptr);
+ InitProperty("C_STANDARD", nullptr);
+ InitProperty("C_STANDARD_REQUIRED", nullptr);
+ InitProperty("C_EXTENSIONS", nullptr);
+ InitProperty("CXX_CLANG_TIDY", nullptr);
+ InitProperty("CXX_COMPILER_LAUNCHER", nullptr);
+ InitProperty("CXX_CPPLINT", nullptr);
+ InitProperty("CXX_CPPCHECK", nullptr);
+ InitProperty("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
+ InitProperty("CXX_STANDARD", nullptr);
+ InitProperty("CXX_STANDARD_REQUIRED", nullptr);
+ InitProperty("CXX_EXTENSIONS", nullptr);
+ InitProperty("CUDA_STANDARD", nullptr);
+ InitProperty("CUDA_STANDARD_REQUIRED", nullptr);
+ InitProperty("CUDA_EXTENSIONS", nullptr);
+ InitProperty("CUDA_COMPILER_LAUNCHER", nullptr);
+ InitProperty("CUDA_SEPARABLE_COMPILATION", nullptr);
+ InitProperty("LINK_SEARCH_START_STATIC", nullptr);
+ InitProperty("LINK_SEARCH_END_STATIC", nullptr);
+ InitProperty("FOLDER", nullptr);
+ InitProperty("Swift_MODULE_DIRECTORY", nullptr);
+ InitProperty("VS_JUST_MY_CODE_DEBUGGING", nullptr);
#ifdef __APPLE__
if (this->GetGlobalGenerator()->IsXcode()) {
- this->SetPropertyDefault("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
- this->SetPropertyDefault(
- "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
- nullptr);
- this->SetPropertyDefault(
- "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_GUARD_MALLOC", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_STACK", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
+ InitProperty("XCODE_GENERATE_SCHEME", nullptr);
+ InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
+ InitProperty("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER", nullptr);
+ InitProperty("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
+ InitProperty("XCODE_SCHEME_GUARD_MALLOC", nullptr);
+ InitProperty("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_STACK", nullptr);
+ InitProperty("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE", nullptr);
+ InitProperty("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
}
#endif
}
- // Collect the set of configuration types.
- std::vector<std::string> configNames;
- mf->GetConfigurations(configNames);
-
// Setup per-configuration property default values.
if (this->GetType() != cmStateEnums::UTILITY) {
- const char* configProps[] = {
+ static const auto configProps = {
/* clang-format needs this comment to break after the opening brace */
"ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_",
"RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_",
"COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
- "INTERPROCEDURAL_OPTIMIZATION_", nullptr
+ "INTERPROCEDURAL_OPTIMIZATION_"
};
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames;
+ mf->GetConfigurations(configNames);
for (std::string const& configName : configNames) {
std::string configUpper = cmSystemTools::UpperCase(configName);
- for (const char** p = configProps; *p; ++p) {
+ for (auto const& prop : configProps) {
// Interface libraries have no output locations, so honor only
// the configuration map.
- if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY &&
- strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0) {
+ if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
+ strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
continue;
}
- std::string property = *p;
+ std::string property = prop;
property += configUpper;
- this->SetPropertyDefault(property, nullptr);
+ InitProperty(property, nullptr);
}
// Initialize per-configuration name postfix property from the
@@ -338,122 +384,93 @@ 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 (this->TargetTypeValue != cmStateEnums::EXECUTABLE &&
- this->TargetTypeValue != cmStateEnums::INTERFACE_LIBRARY) {
+ if (impl->TargetType != cmStateEnums::EXECUTABLE &&
+ impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
std::string property = cmSystemTools::UpperCase(configName);
property += "_POSTFIX";
- this->SetPropertyDefault(property, nullptr);
+ InitProperty(property, nullptr);
}
}
}
// Save the backtrace of target construction.
- this->Backtrace = this->Makefile->GetBacktrace();
+ impl->Backtrace = impl->Makefile->GetBacktrace();
if (!this->IsImported()) {
// Initialize the INCLUDE_DIRECTORIES property based on the current value
// of the same directory property:
- const cmStringRange parentIncludes =
- this->Makefile->GetIncludeDirectoriesEntries();
- const cmBacktraceRange parentIncludesBts =
- this->Makefile->GetIncludeDirectoriesBacktraces();
-
- this->Internal->IncludeDirectoriesEntries.insert(
- this->Internal->IncludeDirectoriesEntries.end(), parentIncludes.begin(),
- parentIncludes.end());
- this->Internal->IncludeDirectoriesBacktraces.insert(
- this->Internal->IncludeDirectoriesBacktraces.end(),
- parentIncludesBts.begin(), parentIncludesBts.end());
-
- const std::set<std::string> parentSystemIncludes =
- this->Makefile->GetSystemIncludeDirectories();
-
- this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
- parentSystemIncludes.end());
-
- const cmStringRange parentCompileOptions =
- this->Makefile->GetCompileOptionsEntries();
- const cmBacktraceRange parentCompileOptionsBts =
- this->Makefile->GetCompileOptionsBacktraces();
-
- this->Internal->CompileOptionsEntries.insert(
- this->Internal->CompileOptionsEntries.end(),
- parentCompileOptions.begin(), parentCompileOptions.end());
- this->Internal->CompileOptionsBacktraces.insert(
- this->Internal->CompileOptionsBacktraces.end(),
- parentCompileOptionsBts.begin(), parentCompileOptionsBts.end());
-
- const cmStringRange parentLinkOptions =
- this->Makefile->GetLinkOptionsEntries();
- const cmBacktraceRange parentLinkOptionsBts =
- this->Makefile->GetLinkOptionsBacktraces();
-
- this->Internal->LinkOptionsEntries.insert(
- this->Internal->LinkOptionsEntries.end(), parentLinkOptions.begin(),
- parentLinkOptions.end());
- this->Internal->LinkOptionsBacktraces.insert(
- this->Internal->LinkOptionsBacktraces.end(),
- parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
-
- const cmStringRange parentLinkDirectories =
- this->Makefile->GetLinkDirectoriesEntries();
- const cmBacktraceRange parentLinkDirectoriesBts =
- this->Makefile->GetLinkDirectoriesBacktraces();
-
- this->Internal->LinkDirectoriesEntries.insert(
- this->Internal->LinkDirectoriesEntries.end(),
- parentLinkDirectories.begin(), parentLinkDirectories.end());
- this->Internal->LinkDirectoriesBacktraces.insert(
- this->Internal->LinkDirectoriesBacktraces.end(),
- parentLinkDirectoriesBts.begin(), parentLinkDirectoriesBts.end());
+ cmAppend(impl->IncludeDirectoriesEntries,
+ impl->Makefile->GetIncludeDirectoriesEntries());
+ cmAppend(impl->IncludeDirectoriesBacktraces,
+ impl->Makefile->GetIncludeDirectoriesBacktraces());
+
+ {
+ auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories();
+ impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end());
+ }
+
+ cmAppend(impl->CompileOptionsEntries,
+ impl->Makefile->GetCompileOptionsEntries());
+ cmAppend(impl->CompileOptionsBacktraces,
+ impl->Makefile->GetCompileOptionsBacktraces());
+
+ cmAppend(impl->LinkOptionsEntries,
+ impl->Makefile->GetLinkOptionsEntries());
+ cmAppend(impl->LinkOptionsBacktraces,
+ impl->Makefile->GetLinkOptionsBacktraces());
+
+ cmAppend(impl->LinkDirectoriesEntries,
+ impl->Makefile->GetLinkDirectoriesEntries());
+ cmAppend(impl->LinkDirectoriesBacktraces,
+ impl->Makefile->GetLinkDirectoriesBacktraces());
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("C_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("CXX_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("CUDA_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", nullptr);
+ InitProperty("C_VISIBILITY_PRESET", nullptr);
+ InitProperty("CXX_VISIBILITY_PRESET", nullptr);
+ InitProperty("CUDA_VISIBILITY_PRESET", nullptr);
+ InitProperty("VISIBILITY_INLINES_HIDDEN", nullptr);
}
- if (this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
- this->SetPropertyDefault("ANDROID_GUI", nullptr);
- this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", nullptr);
- this->SetPropertyDefault("ENABLE_EXPORTS", nullptr);
+ if (impl->TargetType == cmStateEnums::EXECUTABLE) {
+ InitProperty("ANDROID_GUI", nullptr);
+ InitProperty("CROSSCOMPILING_EMULATOR", nullptr);
+ InitProperty("ENABLE_EXPORTS", nullptr);
}
- if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
- this->TargetTypeValue == cmStateEnums::MODULE_LIBRARY) {
+ if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
}
- if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
- this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
- this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
+ if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ impl->TargetType == cmStateEnums::EXECUTABLE) {
+ InitProperty("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", nullptr);
+ InitProperty("POSITION_INDEPENDENT_CODE", nullptr);
}
// Record current policies for later use.
- this->Makefile->RecordPolicies(this->PolicyMap);
+ impl->Makefile->RecordPolicies(impl->PolicyMap);
- if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY) {
+ if (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.
- this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+ impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("JOB_POOL_COMPILE", nullptr);
- this->SetPropertyDefault("JOB_POOL_LINK", nullptr);
+ InitProperty("JOB_POOL_COMPILE", nullptr);
+ InitProperty("JOB_POOL_LINK", nullptr);
}
- if (this->TargetTypeValue <= cmStateEnums::UTILITY) {
- this->SetPropertyDefault("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
+ if (impl->TargetType <= cmStateEnums::UTILITY) {
+ InitProperty("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -474,7 +491,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
if (assignment != std::string::npos) {
const std::string propName = vsGlobal + i.substr(0, assignment);
const std::string propValue = i.substr(assignment + 1);
- this->SetPropertyDefault(propName, propValue.c_str());
+ InitProperty(propName, propValue.c_str());
}
}
}
@@ -482,20 +499,56 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
}
}
+cmTarget::cmTarget(cmTarget&&) noexcept = default;
+cmTarget::~cmTarget() = default;
+
+cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
+
+cmStateEnums::TargetType cmTarget::GetType() const
+{
+ return impl->TargetType;
+}
+
+cmMakefile* cmTarget::GetMakefile() const
+{
+ return impl->Makefile;
+}
+
+cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
+{
+ return impl->PolicyMap;
+}
+
+const std::string& cmTarget::GetName() const
+{
+ return impl->Name;
+}
+
+cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
+ cmPolicies::PolicyID policy) const
+{
+ return impl->PolicyMap.Get(policy);
+}
+
cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
{
- return this->GetMakefile()->GetGlobalGenerator();
+ return impl->Makefile->GetGlobalGenerator();
+}
+
+void cmTarget::AddUtility(std::string const& name, cmMakefile* mf)
+{
+ impl->Utilities.insert(
+ BT<std::string>(name, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
}
-void cmTarget::AddUtility(std::string const& u, cmMakefile* mf)
+std::set<BT<std::string>> const& cmTarget::GetUtilities() const
{
- BT<std::string> util(u, mf ? mf->GetBacktrace() : cmListFileBacktrace());
- this->Utilities.insert(util);
+ return impl->Utilities;
}
cmListFileBacktrace const& cmTarget::GetBacktrace() const
{
- return this->Backtrace;
+ return impl->Backtrace;
}
bool cmTarget::IsExecutableWithExports() const
@@ -504,34 +557,57 @@ bool cmTarget::IsExecutableWithExports() const
this->GetPropertyAsBool("ENABLE_EXPORTS"));
}
-bool cmTarget::HasImportLibrary() const
-{
- return (this->DLLPlatform &&
- (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
- this->IsExecutableWithExports()));
-}
-
bool cmTarget::IsFrameworkOnApple() const
{
return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
- this->Makefile->IsOn("APPLE") &&
+ impl->Makefile->IsOn("APPLE") &&
this->GetPropertyAsBool("FRAMEWORK"));
}
bool cmTarget::IsAppBundleOnApple() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE &&
- this->Makefile->IsOn("APPLE") &&
+ impl->Makefile->IsOn("APPLE") &&
this->GetPropertyAsBool("MACOSX_BUNDLE"));
}
+std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
+{
+ return impl->PreBuildCommands;
+}
+
+void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
+{
+ impl->PreBuildCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
+{
+ return impl->PreLinkCommands;
+}
+
+void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
+{
+ impl->PreLinkCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
+{
+ return impl->PostBuildCommands;
+}
+
+void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
+{
+ impl->PostBuildCommands.push_back(cmd);
+}
+
void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
if (!srcs.empty()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.push_back(cmJoin(srcs, ";"));
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.push_back(cmJoin(srcs, ";"));
+ impl->SourceBacktraces.push_back(lfbt);
}
}
@@ -542,25 +618,25 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
for (auto filename : srcs) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
- filename = this->ProcessSourceItemCMP0049(filename);
+ filename = impl->ProcessSourceItemCMP0049(filename);
if (filename.empty()) {
return;
}
}
- this->Makefile->GetOrCreateSource(filename);
+ impl->Makefile->GetOrCreateSource(filename);
}
srcFiles += sep;
srcFiles += filename;
sep = ";";
}
if (!srcFiles.empty()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.push_back(std::move(srcFiles));
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.push_back(std::move(srcFiles));
+ impl->SourceBacktraces.push_back(lfbt);
}
}
-std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
+std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s)
{
std::string src = s;
@@ -585,7 +661,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
}
if (!noMessage) {
e << "Legacy variable expansion in source file \"" << s
- << "\" expanded to \"" << src << "\" in target \"" << this->GetName()
+ << "\" expanded to \"" << src << "\" in target \"" << this->Name
<< "\". This behavior will be removed in a "
"future version of CMake.";
this->Makefile->IssueMessage(messageType, e.str());
@@ -599,7 +675,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
{
- std::string src = this->ProcessSourceItemCMP0049(s);
+ std::string src = impl->ProcessSourceItemCMP0049(s);
if (!s.empty() && src.empty()) {
return nullptr;
}
@@ -663,26 +739,22 @@ public:
cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
{
- cmSourceFileLocation sfl(this->Makefile, src,
+ cmSourceFileLocation sfl(impl->Makefile, src,
cmSourceFileLocationKind::Known);
- if (std::find_if(this->Internal->SourceEntries.begin(),
- this->Internal->SourceEntries.end(),
+ if (std::find_if(impl->SourceEntries.begin(), impl->SourceEntries.end(),
TargetPropertyEntryFinder(sfl)) ==
- this->Internal->SourceEntries.end()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.insert(
- before ? this->Internal->SourceEntries.begin()
- : this->Internal->SourceEntries.end(),
- src);
- this->Internal->SourceBacktraces.insert(
- before ? this->Internal->SourceBacktraces.begin()
- : this->Internal->SourceBacktraces.end(),
- lfbt);
+ 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 (cmGeneratorExpression::Find(src) != std::string::npos) {
return nullptr;
}
- return this->Makefile->GetOrCreateSource(src, false,
+ return impl->Makefile->GetOrCreateSource(src, false,
cmSourceFileLocationKind::Known);
}
@@ -702,15 +774,13 @@ std::string cmTarget::GetDebugGeneratorExpressions(
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> debugConfigs =
- this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+ impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
if (debugConfigs.size() > 1) {
- for (std::vector<std::string>::const_iterator li =
- debugConfigs.begin() + 1;
- li != debugConfigs.end(); ++li) {
- configString += ",$<CONFIG:" + *li + ">";
+ for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
+ configString += ",$<CONFIG:" + conf + ">";
}
configString = "$<OR:" + configString + ">";
}
@@ -730,13 +800,13 @@ bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
cmListFileContext const& lfc)
{
bool ret = true;
- if (!this->TLLCommands.empty()) {
- if (this->TLLCommands.back().first != signature) {
+ if (!impl->TLLCommands.empty()) {
+ if (impl->TLLCommands.back().first != signature) {
ret = false;
}
}
- if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc) {
- this->TLLCommands.emplace_back(signature, lfc);
+ if (impl->TLLCommands.empty() || impl->TLLCommands.back().second != lfc) {
+ impl->TLLCommands.emplace_back(signature, lfc);
}
return ret;
}
@@ -746,18 +816,63 @@ 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 =
- this->GetMakefile()->GetStateSnapshot().GetDirectory();
- for (auto const& cmd : this->TLLCommands) {
+ cmStateDirectory cmDir = impl->Makefile->GetStateSnapshot().GetDirectory();
+ for (auto const& cmd : impl->TLLCommands) {
if (cmd.first == sig) {
cmListFileContext lfc = cmd.second;
lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
- this->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
+ impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
s << " * " << lfc << std::endl;
}
}
}
+std::string const& cmTarget::GetInstallPath() const
+{
+ return impl->InstallPath;
+}
+
+void cmTarget::SetInstallPath(std::string const& name)
+{
+ impl->InstallPath = name;
+}
+
+std::string const& cmTarget::GetRuntimeInstallPath() const
+{
+ return impl->RuntimeInstallPath;
+}
+
+void cmTarget::SetRuntimeInstallPath(std::string const& name)
+{
+ impl->RuntimeInstallPath = name;
+}
+
+bool cmTarget::GetHaveInstallRule() const
+{
+ return impl->HaveInstallRule;
+}
+
+void cmTarget::SetHaveInstallRule(bool hir)
+{
+ impl->HaveInstallRule = hir;
+}
+
+bool cmTarget::GetIsGeneratorProvided() const
+{
+ return impl->IsGeneratorProvided;
+}
+
+void cmTarget::SetIsGeneratorProvided(bool igp)
+{
+ impl->IsGeneratorProvided = igp;
+}
+
+cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
+ const
+{
+ return impl->OriginalLinkLibraries;
+}
+
void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
cmTargetLinkLibraryType llt)
{
@@ -785,11 +900,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
(tgt &&
(tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
- (this->Name == lib)) {
+ (impl->Name == lib)) {
return;
}
- this->OriginalLinkLibraries.emplace_back(lib, llt);
+ 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
@@ -799,11 +914,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 (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY &&
- this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY &&
+ if (impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
+ impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
(this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
- std::string targetEntry = this->Name;
+ std::string targetEntry = impl->Name;
targetEntry += "_LIB_DEPENDS";
std::string dependencies;
const char* old_val = mf.GetDefinition(targetEntry);
@@ -831,94 +946,99 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
{
- this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+ impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
+{
+ return impl->SystemIncludeDirectories;
}
cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
{
- return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
+ return cmMakeRange(impl->IncludeDirectoriesEntries);
}
cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
{
- return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
+ return cmMakeRange(impl->IncludeDirectoriesBacktraces);
}
cmStringRange cmTarget::GetCompileOptionsEntries() const
{
- return cmMakeRange(this->Internal->CompileOptionsEntries);
+ return cmMakeRange(impl->CompileOptionsEntries);
}
cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
{
- return cmMakeRange(this->Internal->CompileOptionsBacktraces);
+ return cmMakeRange(impl->CompileOptionsBacktraces);
}
cmStringRange cmTarget::GetCompileFeaturesEntries() const
{
- return cmMakeRange(this->Internal->CompileFeaturesEntries);
+ return cmMakeRange(impl->CompileFeaturesEntries);
}
cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
{
- return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
+ return cmMakeRange(impl->CompileFeaturesBacktraces);
}
cmStringRange cmTarget::GetCompileDefinitionsEntries() const
{
- return cmMakeRange(this->Internal->CompileDefinitionsEntries);
+ return cmMakeRange(impl->CompileDefinitionsEntries);
}
cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
{
- return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
+ return cmMakeRange(impl->CompileDefinitionsBacktraces);
}
cmStringRange cmTarget::GetSourceEntries() const
{
- return cmMakeRange(this->Internal->SourceEntries);
+ return cmMakeRange(impl->SourceEntries);
}
cmBacktraceRange cmTarget::GetSourceBacktraces() const
{
- return cmMakeRange(this->Internal->SourceBacktraces);
+ return cmMakeRange(impl->SourceBacktraces);
}
cmStringRange cmTarget::GetLinkOptionsEntries() const
{
- return cmMakeRange(this->Internal->LinkOptionsEntries);
+ return cmMakeRange(impl->LinkOptionsEntries);
}
cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
{
- return cmMakeRange(this->Internal->LinkOptionsBacktraces);
+ return cmMakeRange(impl->LinkOptionsBacktraces);
}
cmStringRange cmTarget::GetLinkDirectoriesEntries() const
{
- return cmMakeRange(this->Internal->LinkDirectoriesEntries);
+ return cmMakeRange(impl->LinkDirectoriesEntries);
}
cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
{
- return cmMakeRange(this->Internal->LinkDirectoriesBacktraces);
+ return cmMakeRange(impl->LinkDirectoriesBacktraces);
}
cmStringRange cmTarget::GetLinkImplementationEntries() const
{
- return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
+ return cmMakeRange(impl->LinkImplementationPropertyEntries);
}
cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
{
- return cmMakeRange(this->Internal->LinkImplementationPropertyBacktraces);
+ return cmMakeRange(impl->LinkImplementationPropertyBacktraces);
}
void cmTarget::SetProperty(const std::string& prop, const char* value)
{
if (!cmTargetPropertyComputer::PassesWhitelist(
- this->GetType(), prop, this->Makefile->GetMessenger(),
- this->Makefile->GetBacktrace())) {
+ this->GetType(), prop, impl->Makefile->GetMessenger(),
+ impl->Makefile->GetBacktrace())) {
return;
}
#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
@@ -940,133 +1060,133 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
std::ostringstream e;
e << "MANUALLY_ADDED_DEPENDENCIES property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propNAME) {
std::ostringstream e;
e << "NAME property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propTYPE) {
std::ostringstream e;
e << "TYPE property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propEXPORT_NAME && this->IsImported()) {
std::ostringstream e;
e << "EXPORT_NAME property can't be set on imported targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ 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 (\"" << this->Name
+ e << "SOURCES property can't be set on imported targets (\"" << impl->Name
<< "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ 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 (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propINCLUDE_DIRECTORIES) {
- this->Internal->IncludeDirectoriesEntries.clear();
- this->Internal->IncludeDirectoriesBacktraces.clear();
+ impl->IncludeDirectoriesEntries.clear();
+ impl->IncludeDirectoriesBacktraces.clear();
if (value) {
- this->Internal->IncludeDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->IncludeDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_OPTIONS) {
- this->Internal->CompileOptionsEntries.clear();
- this->Internal->CompileOptionsBacktraces.clear();
+ impl->CompileOptionsEntries.clear();
+ impl->CompileOptionsBacktraces.clear();
if (value) {
- this->Internal->CompileOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileOptionsBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_FEATURES) {
- this->Internal->CompileFeaturesEntries.clear();
- this->Internal->CompileFeaturesBacktraces.clear();
+ impl->CompileFeaturesEntries.clear();
+ impl->CompileFeaturesBacktraces.clear();
if (value) {
- this->Internal->CompileFeaturesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileFeaturesBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_DEFINITIONS) {
- this->Internal->CompileDefinitionsEntries.clear();
- this->Internal->CompileDefinitionsBacktraces.clear();
+ impl->CompileDefinitionsEntries.clear();
+ impl->CompileDefinitionsBacktraces.clear();
if (value) {
- this->Internal->CompileDefinitionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileDefinitionsBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_OPTIONS) {
- this->Internal->LinkOptionsEntries.clear();
- this->Internal->LinkOptionsBacktraces.clear();
+ impl->LinkOptionsEntries.clear();
+ impl->LinkOptionsBacktraces.clear();
if (value) {
- this->Internal->LinkOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+ impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_DIRECTORIES) {
- this->Internal->LinkDirectoriesEntries.clear();
- this->Internal->LinkDirectoriesBacktraces.clear();
+ impl->LinkDirectoriesEntries.clear();
+ impl->LinkDirectoriesBacktraces.clear();
if (value) {
- this->Internal->LinkDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_LIBRARIES) {
- this->Internal->LinkImplementationPropertyEntries.clear();
- this->Internal->LinkImplementationPropertyBacktraces.clear();
+ impl->LinkImplementationPropertyEntries.clear();
+ impl->LinkImplementationPropertyBacktraces.clear();
if (value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
- this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkImplementationPropertyEntries.emplace_back(value);
+ impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
}
} else if (prop == propSOURCES) {
- this->Internal->SourceEntries.clear();
- this->Internal->SourceBacktraces.clear();
+ impl->SourceEntries.clear();
+ impl->SourceBacktraces.clear();
if (value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.emplace_back(value);
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.emplace_back(value);
+ impl->SourceBacktraces.push_back(lfbt);
}
} else if (prop == propIMPORTED_GLOBAL) {
if (!cmSystemTools::IsOn(value)) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
/* no need to change anything if value does not change */
- if (!this->ImportedGloballyVisible) {
- this->ImportedGloballyVisible = true;
+ if (!impl->ImportedGloballyVisible) {
+ impl->ImportedGloballyVisible = true;
this->GetGlobalGenerator()->IndexTarget(this);
}
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
- !this->CheckImportedLibName(prop, value ? value : "")) {
+ !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 (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
} else {
- this->Properties.SetProperty(prop, value);
+ impl->Properties.SetProperty(prop, value);
}
}
@@ -1074,89 +1194,89 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
bool asString)
{
if (!cmTargetPropertyComputer::PassesWhitelist(
- this->GetType(), prop, this->Makefile->GetMessenger(),
- this->Makefile->GetBacktrace())) {
+ this->GetType(), prop, impl->Makefile->GetMessenger(),
+ impl->Makefile->GetBacktrace())) {
return;
}
if (prop == "NAME") {
std::ostringstream e;
e << "NAME property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "EXPORT_NAME" && this->IsImported()) {
std::ostringstream e;
e << "EXPORT_NAME property can't be set on imported targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ 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 (\"" << this->Name
+ e << "SOURCES property can't be set on imported targets (\"" << impl->Name
<< "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ 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 (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "INCLUDE_DIRECTORIES") {
if (value && *value) {
- this->Internal->IncludeDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->IncludeDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_OPTIONS") {
if (value && *value) {
- this->Internal->CompileOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileOptionsBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_FEATURES") {
if (value && *value) {
- this->Internal->CompileFeaturesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileFeaturesBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_DEFINITIONS") {
if (value && *value) {
- this->Internal->CompileDefinitionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileDefinitionsBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_OPTIONS") {
if (value && *value) {
- this->Internal->LinkOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+ impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_DIRECTORIES") {
if (value && *value) {
- this->Internal->LinkDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_LIBRARIES") {
if (value && *value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
- this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkImplementationPropertyEntries.emplace_back(value);
+ impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
}
} else if (prop == "SOURCES") {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.emplace_back(value);
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.emplace_back(value);
+ impl->SourceBacktraces.push_back(lfbt);
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
prop + " property may not be APPENDed.");
} else {
- this->Properties.AppendProperty(prop, value, asString);
+ impl->Properties.AppendProperty(prop, value, asString);
}
}
@@ -1169,17 +1289,17 @@ void cmTarget::AppendBuildInterfaceIncludes()
!this->IsExecutableWithExports()) {
return;
}
- if (this->BuildInterfaceIncludesAppended) {
+ if (impl->BuildInterfaceIncludesAppended) {
return;
}
- this->BuildInterfaceIncludesAppended = true;
+ impl->BuildInterfaceIncludesAppended = true;
- if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
- std::string dirs = this->Makefile->GetCurrentBinaryDirectory();
+ if (impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+ std::string dirs = impl->Makefile->GetCurrentBinaryDirectory();
if (!dirs.empty()) {
dirs += ';';
}
- dirs += this->Makefile->GetCurrentSourceDirectory();
+ dirs += impl->Makefile->GetCurrentSourceDirectory();
if (!dirs.empty()) {
this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
("$<BUILD_INTERFACE:" + dirs + ">").c_str());
@@ -1191,67 +1311,66 @@ void cmTarget::InsertInclude(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->IncludeDirectoriesEntries.begin()
- : this->Internal->IncludeDirectoriesEntries.end();
+ ? impl->IncludeDirectoriesEntries.begin()
+ : impl->IncludeDirectoriesEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->IncludeDirectoriesBacktraces.begin()
- : this->Internal->IncludeDirectoriesBacktraces.end();
+ ? impl->IncludeDirectoriesBacktraces.begin()
+ : impl->IncludeDirectoriesBacktraces.end();
- this->Internal->IncludeDirectoriesEntries.insert(position, entry);
- this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+ impl->IncludeDirectoriesEntries.insert(position, entry);
+ impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertCompileOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->CompileOptionsEntries.begin()
- : this->Internal->CompileOptionsEntries.end();
+ ? impl->CompileOptionsEntries.begin()
+ : impl->CompileOptionsEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->CompileOptionsBacktraces.begin()
- : this->Internal->CompileOptionsBacktraces.end();
+ ? impl->CompileOptionsBacktraces.begin()
+ : impl->CompileOptionsBacktraces.end();
- this->Internal->CompileOptionsEntries.insert(position, entry);
- this->Internal->CompileOptionsBacktraces.insert(btPosition, bt);
+ impl->CompileOptionsEntries.insert(position, entry);
+ impl->CompileOptionsBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertCompileDefinition(std::string const& entry,
cmListFileBacktrace const& bt)
{
- this->Internal->CompileDefinitionsEntries.push_back(entry);
- this->Internal->CompileDefinitionsBacktraces.push_back(bt);
+ impl->CompileDefinitionsEntries.push_back(entry);
+ impl->CompileDefinitionsBacktraces.push_back(bt);
}
void cmTarget::InsertLinkOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
- std::vector<std::string>::iterator position = before
- ? this->Internal->LinkOptionsEntries.begin()
- : this->Internal->LinkOptionsEntries.end();
+ std::vector<std::string>::iterator position =
+ before ? impl->LinkOptionsEntries.begin() : impl->LinkOptionsEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->LinkOptionsBacktraces.begin()
- : this->Internal->LinkOptionsBacktraces.end();
+ ? impl->LinkOptionsBacktraces.begin()
+ : impl->LinkOptionsBacktraces.end();
- this->Internal->LinkOptionsEntries.insert(position, entry);
- this->Internal->LinkOptionsBacktraces.insert(btPosition, bt);
+ impl->LinkOptionsEntries.insert(position, entry);
+ impl->LinkOptionsBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertLinkDirectory(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->LinkDirectoriesEntries.begin()
- : this->Internal->LinkDirectoriesEntries.end();
+ ? impl->LinkDirectoriesEntries.begin()
+ : impl->LinkDirectoriesEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->LinkDirectoriesBacktraces.begin()
- : this->Internal->LinkDirectoriesBacktraces.end();
+ ? impl->LinkDirectoriesBacktraces.begin()
+ : impl->LinkDirectoriesBacktraces.end();
- this->Internal->LinkDirectoriesEntries.insert(position, entry);
- this->Internal->LinkDirectoriesBacktraces.insert(btPosition, bt);
+ impl->LinkDirectoriesEntries.insert(position, entry);
+ impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
}
static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
@@ -1402,12 +1521,12 @@ const char* cmTarget::GetProperty(const std::string& prop) const
}
if (specialProps.count(prop)) {
if (prop == propLINK_LIBRARIES) {
- if (this->Internal->LinkImplementationPropertyEntries.empty()) {
+ if (impl->LinkImplementationPropertyEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkImplementationPropertyEntries, ";");
+ output = cmJoin(impl->LinkImplementationPropertyEntries, ";");
return output.c_str();
}
// the type property returns what type the target is
@@ -1415,67 +1534,67 @@ const char* cmTarget::GetProperty(const std::string& prop) const
return cmState::GetTargetTypeName(this->GetType());
}
if (prop == propINCLUDE_DIRECTORIES) {
- if (this->Internal->IncludeDirectoriesEntries.empty()) {
+ if (impl->IncludeDirectoriesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
+ output = cmJoin(impl->IncludeDirectoriesEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_FEATURES) {
- if (this->Internal->CompileFeaturesEntries.empty()) {
+ if (impl->CompileFeaturesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
+ output = cmJoin(impl->CompileFeaturesEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_OPTIONS) {
- if (this->Internal->CompileOptionsEntries.empty()) {
+ if (impl->CompileOptionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileOptionsEntries, ";");
+ output = cmJoin(impl->CompileOptionsEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_DEFINITIONS) {
- if (this->Internal->CompileDefinitionsEntries.empty()) {
+ if (impl->CompileDefinitionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
+ output = cmJoin(impl->CompileDefinitionsEntries, ";");
return output.c_str();
}
if (prop == propLINK_OPTIONS) {
- if (this->Internal->LinkOptionsEntries.empty()) {
+ if (impl->LinkOptionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkOptionsEntries, ";");
+ output = cmJoin(impl->LinkOptionsEntries, ";");
return output.c_str();
}
if (prop == propLINK_DIRECTORIES) {
- if (this->Internal->LinkDirectoriesEntries.empty()) {
+ if (impl->LinkDirectoriesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkDirectoriesEntries, ";");
+ output = cmJoin(impl->LinkDirectoriesEntries, ";");
return output.c_str();
}
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
- if (this->Utilities.empty()) {
+ if (impl->Utilities.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Utilities, ";");
+ output = cmJoin(impl->Utilities, ";");
return output.c_str();
}
if (prop == propIMPORTED) {
@@ -1488,27 +1607,25 @@ const char* cmTarget::GetProperty(const std::string& prop) const
return this->GetName().c_str();
}
if (prop == propBINARY_DIR) {
- return this->GetMakefile()
- ->GetStateSnapshot()
+ return impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentBinary()
.c_str();
}
if (prop == propSOURCE_DIR) {
- return this->GetMakefile()
- ->GetStateSnapshot()
+ return impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentSource()
.c_str();
}
}
- const char* retVal = this->Properties.GetPropertyValue(prop);
+ const char* retVal = impl->Properties.GetPropertyValue(prop);
if (!retVal) {
- const bool chain = this->GetMakefile()->GetState()->IsPropertyChained(
- prop, cmProperty::TARGET);
+ const bool chain =
+ impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET);
if (chain) {
- return this->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
+ return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
prop, chain);
}
}
@@ -1529,6 +1646,21 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
return cmSystemTools::IsOn(this->GetProperty(prop));
}
+cmPropertyMap const& cmTarget::GetProperties() const
+{
+ return impl->Properties;
+}
+
+bool cmTarget::IsImported() const
+{
+ return impl->IsImportedTarget;
+}
+
+bool cmTarget::IsImportedGloballyVisible() const
+{
+ return impl->ImportedGloballyVisible;
+}
+
const char* cmTarget::GetSuffixVariableInternal(
cmStateEnums::ArtifactType artifact) const
{
@@ -1556,7 +1688,7 @@ const char* cmTarget::GetSuffixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
- return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
? "CMAKE_SHARED_LIBRARY_SUFFIX"
: "CMAKE_EXECUTABLE_SUFFIX");
case cmStateEnums::ImportLibraryArtifact:
@@ -1596,7 +1728,7 @@ const char* cmTarget::GetPrefixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
- return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
? "CMAKE_SHARED_LIBRARY_PREFIX"
: "");
case cmStateEnums::ImportLibraryArtifact:
@@ -1670,25 +1802,11 @@ std::string cmTarget::ImportedGetFullPath(
return result;
}
-void cmTarget::SetPropertyDefault(const std::string& property,
- const char* default_value)
-{
- // Compute the name of the variable holding the default value.
- std::string var = "CMAKE_";
- var += property;
-
- if (const char* value = this->Makefile->GetDefinition(var)) {
- this->SetProperty(property, value);
- } else if (default_value) {
- this->SetProperty(property, default_value);
- }
-}
-
-bool cmTarget::CheckImportedLibName(std::string const& prop,
- std::string const& value) const
+bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
+ std::string const& value) const
{
- if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY ||
- !this->IsImported()) {
+ if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
+ !this->IsImportedTarget) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
prop +
@@ -1748,7 +1866,9 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
// If we needed to find one of the mapped configurations but did not
// On a DLL platform there may be only IMPORTED_IMPLIB for a shared
// library or an executable with exports.
- bool allowImp = this->HasImportLibrary();
+ bool allowImp = (impl->DLLPlatform &&
+ (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()));
// If a mapping was found, check its configurations.
for (std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
@@ -1851,37 +1971,3 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
return true;
}
-
-cmTargetInternalPointer::cmTargetInternalPointer()
-{
- this->Pointer = new cmTargetInternals;
-}
-
-cmTargetInternalPointer::cmTargetInternalPointer(
- cmTargetInternalPointer const& r)
-{
- // Ideally cmTarget instances should never be copied. However until
- // we can make a sweep to remove that, this copy constructor avoids
- // allowing the resources (Internals) to be copied.
- this->Pointer = new cmTargetInternals(*r.Pointer);
-}
-
-cmTargetInternalPointer::~cmTargetInternalPointer()
-{
- delete this->Pointer;
-}
-
-cmTargetInternalPointer& cmTargetInternalPointer::operator=(
- cmTargetInternalPointer const& r)
-{
- if (this == &r) {
- return *this;
- } // avoid warning on HP about self check
- // Ideally cmTarget instances should never be copied. However until
- // we can make a sweep to remove that, this copy constructor avoids
- // allowing the resources (Internals) to be copied.
- cmTargetInternals* oldPointer = this->Pointer;
- this->Pointer = new cmTargetInternals(*r.Pointer);
- delete oldPointer;
- return *this;
-}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 24b37423e..fdcca47b8 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -6,45 +6,30 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
-#include <unordered_map>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
-#include "cmCustomCommand.h"
#include "cmListFileCache.h"
#include "cmPolicies.h"
-#include "cmPropertyMap.h"
#include "cmStateTypes.h"
#include "cmTargetLinkLibraryType.h"
+class cmCustomCommand;
class cmGlobalGenerator;
class cmMakefile;
class cmMessenger;
+class cmPropertyMap;
class cmSourceFile;
class cmTargetInternals;
-class cmTargetInternalPointer
-{
-public:
- cmTargetInternalPointer();
- cmTargetInternalPointer(cmTargetInternalPointer const& r);
- ~cmTargetInternalPointer();
- cmTargetInternalPointer& operator=(cmTargetInternalPointer const& r);
- cmTargetInternals* operator->() const { return this->Pointer; }
- cmTargetInternals* Get() const { return this->Pointer; }
-
-private:
- cmTargetInternals* Pointer;
-};
-
/** \class cmTarget
* \brief Represent a library or executable target loaded from a makefile.
*
- * cmTarget represents a target loaded from
- * a makefile.
+ * cmTarget represents a target loaded from a makefile.
*/
class cmTarget
{
@@ -56,9 +41,6 @@ public:
VisibilityImportedGlobally
};
- cmTarget(std::string const& name, cmStateEnums::TargetType type,
- Visibility vis, cmMakefile* mf);
-
enum CustomCommandType
{
PRE_BUILD,
@@ -66,77 +48,68 @@ public:
POST_BUILD
};
- /**
- * Return the type of target.
- */
- cmStateEnums::TargetType GetType() const { return this->TargetTypeValue; }
+ cmTarget(std::string const& name, cmStateEnums::TargetType type,
+ Visibility vis, cmMakefile* mf);
+
+ cmTarget(cmTarget const&) = delete;
+ cmTarget(cmTarget&&) noexcept;
+ ~cmTarget();
+ cmTarget& operator=(cmTarget const&) = delete;
+ cmTarget& operator=(cmTarget&&) noexcept;
+
+ //! Return the type of target.
+ cmStateEnums::TargetType GetType() const;
+
+ //! Get the cmMakefile that owns this target.
+ cmMakefile* GetMakefile() const;
+
+ //! Return the global generator.
cmGlobalGenerator* GetGlobalGenerator() const;
- ///! Set/Get the name of the target
- const std::string& GetName() const { return this->Name; }
+ //! Set/Get the name of the target
+ const std::string& GetName() const;
+
+ //! Get the policy map
+ cmPolicies::PolicyMap const& GetPolicyMap() const;
- /** Get the cmMakefile that owns this target. */
- cmMakefile* GetMakefile() const { return this->Makefile; }
+ //! Get policy status
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID policy) const;
#define DECLARE_TARGET_POLICY(POLICY) \
cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
{ \
- return this->PolicyMap.Get(cmPolicies::POLICY); \
+ return this->GetPolicyStatus(cmPolicies::POLICY); \
}
CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
#undef DECLARE_TARGET_POLICY
- /**
- * Get the list of the custom commands for this target
- */
- std::vector<cmCustomCommand> const& GetPreBuildCommands() const
- {
- return this->PreBuildCommands;
- }
- std::vector<cmCustomCommand> const& GetPreLinkCommands() const
- {
- return this->PreLinkCommands;
- }
- std::vector<cmCustomCommand> const& GetPostBuildCommands() const
- {
- return this->PostBuildCommands;
- }
- void AddPreBuildCommand(cmCustomCommand const& cmd)
- {
- this->PreBuildCommands.push_back(cmd);
- }
- void AddPreLinkCommand(cmCustomCommand const& cmd)
- {
- this->PreLinkCommands.push_back(cmd);
- }
- void AddPostBuildCommand(cmCustomCommand const& cmd)
- {
- this->PostBuildCommands.push_back(cmd);
- }
+ //! Get the list of the PRE_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+ void AddPreBuildCommand(cmCustomCommand const& cmd);
- /**
- * Add sources to the target.
- */
+ //! Get the list of the PRE_LINK custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+ void AddPreLinkCommand(cmCustomCommand const& cmd);
+
+ //! Get the list of the POST_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+ void AddPostBuildCommand(cmCustomCommand const& cmd);
+
+ //! Add sources to the target.
void AddSources(std::vector<std::string> const& srcs);
void AddTracedSources(std::vector<std::string> const& srcs);
cmSourceFile* AddSourceCMP0049(const std::string& src);
cmSourceFile* AddSource(const std::string& src, bool before = false);
- //* how we identify a library, by name and type
+ //! how we identify a library, by name and type
typedef std::pair<std::string, cmTargetLinkLibraryType> LibraryID;
-
typedef std::vector<LibraryID> LinkLibraryVectorType;
- const LinkLibraryVectorType& GetOriginalLinkLibraries() const
- {
- return this->OriginalLinkLibraries;
- }
+ LinkLibraryVectorType const& GetOriginalLinkLibraries() const;
- /**
- * Clear the dependency information recorded for this target, if any.
- */
+ //! Clear the dependency information recorded for this target, if any.
void ClearDependencyInformation(cmMakefile& mf);
void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
@@ -157,83 +130,69 @@ public:
* Set the path where this target should be installed. This is relative to
* INSTALL_PREFIX
*/
- std::string GetInstallPath() const { return this->InstallPath; }
- void SetInstallPath(const char* name) { this->InstallPath = name; }
+ std::string const& GetInstallPath() const;
+ void SetInstallPath(std::string const& name);
/**
* Set the path where this target (if it has a runtime part) should be
* installed. This is relative to INSTALL_PREFIX
*/
- std::string GetRuntimeInstallPath() const
- {
- return this->RuntimeInstallPath;
- }
- void SetRuntimeInstallPath(const char* name)
- {
- this->RuntimeInstallPath = name;
- }
+ std::string const& GetRuntimeInstallPath() const;
+ void SetRuntimeInstallPath(std::string const& name);
/**
* Get/Set whether there is an install rule for this target.
*/
- bool GetHaveInstallRule() const { return this->HaveInstallRule; }
- void SetHaveInstallRule(bool h) { this->HaveInstallRule = h; }
+ bool GetHaveInstallRule() const;
+ void SetHaveInstallRule(bool hir);
/**
* Get/Set whether this target was auto-created by a generator.
*/
- bool GetIsGeneratorProvided() const { return this->IsGeneratorProvided; }
- void SetIsGeneratorProvided(bool igp) { this->IsGeneratorProvided = igp; }
+ bool GetIsGeneratorProvided() const;
+ void SetIsGeneratorProvided(bool igp);
- /** Add a utility on which this project depends. A utility is an executable
+ /**
+ * Add a utility on which this project depends. A utility is an executable
* name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE
* commands. It is not a full path nor does it have an extension.
*/
- void AddUtility(std::string const& u, cmMakefile* mf = nullptr);
- ///! Get the utilities used by this target
- std::set<BT<std::string>> const& GetUtilities() const
- {
- return this->Utilities;
- }
+ void AddUtility(std::string const& name, cmMakefile* mf = nullptr);
+ //! Get the utilities used by this target
+ std::set<BT<std::string>> const& GetUtilities() const;
- ///! Set/Get a property of this target file
+ //! Set/Get a property of this target file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
void CheckProperty(const std::string& prop, cmMakefile* context) const;
const char* GetComputedProperty(const std::string& prop,
cmMessenger* messenger,
cmListFileBacktrace const& context) const;
+ //! Get all properties
+ cmPropertyMap const& GetProperties() const;
- bool IsImported() const { return this->IsImportedTarget; }
- bool IsImportedGloballyVisible() const
- {
- return this->ImportedGloballyVisible;
- }
-
- // Get the properties
- cmPropertyMap const& GetProperties() const { return this->Properties; }
+ bool IsImported() const;
+ bool IsImportedGloballyVisible() const;
bool GetMappedConfig(std::string const& desired_config, const char** loc,
const char** imp, std::string& suffix) const;
- /** Return whether this target is an executable with symbol exports
- enabled. */
+ //! Return whether this target is an executable with symbol exports enabled.
bool IsExecutableWithExports() const;
- /** Return whether this target is a shared library Framework on
- Apple. */
+ //! Return whether this target is a shared library Framework on Apple.
bool IsFrameworkOnApple() const;
- /** Return whether this target is an executable Bundle on Apple. */
+ //! Return whether this target is an executable Bundle on Apple.
bool IsAppBundleOnApple() const;
- /** Get a backtrace from the creation of the target. */
+ //! Get a backtrace from the creation of the target.
cmListFileBacktrace const& GetBacktrace() const;
void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
@@ -252,11 +211,8 @@ public:
std::string GetDebugGeneratorExpressions(const std::string& value,
cmTargetLinkLibraryType llt) const;
- void AddSystemIncludeDirectories(const std::set<std::string>& incs);
- std::set<std::string> const& GetSystemIncludeDirectories() const
- {
- return this->SystemIncludeDirectories;
- }
+ void AddSystemIncludeDirectories(std::set<std::string> const& incs);
+ std::set<std::string> const& GetSystemIncludeDirectories() const;
cmStringRange GetIncludeDirectoriesEntries() const;
cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
@@ -282,65 +238,25 @@ public:
cmStringRange GetLinkImplementationEntries() const;
cmBacktraceRange GetLinkImplementationBacktraces() const;
+ std::string ImportedGetFullPath(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
struct StrictTargetComparison
{
bool operator()(cmTarget const* t1, cmTarget const* t2) const;
};
- std::string ImportedGetFullPath(const std::string& config,
- cmStateEnums::ArtifactType artifact) const;
-
private:
+ // Internal representation details.
+ friend class cmGeneratorTarget;
+
const char* GetSuffixVariableInternal(
cmStateEnums::ArtifactType artifact) const;
const char* GetPrefixVariableInternal(
cmStateEnums::ArtifactType artifact) const;
- // Use a makefile variable to set a default for the given property.
- // If the variable is not defined use the given default instead.
- void SetPropertyDefault(const std::string& property,
- const char* default_value);
-
- bool CheckImportedLibName(std::string const& prop,
- std::string const& value) const;
-
private:
- bool IsGeneratorProvided;
- cmPropertyMap Properties;
- std::set<std::string> SystemIncludeDirectories;
- std::set<BT<std::string>> Utilities;
- cmPolicies::PolicyMap PolicyMap;
- std::string Name;
- std::string InstallPath;
- std::string RuntimeInstallPath;
- std::vector<cmCustomCommand> PreBuildCommands;
- std::vector<cmCustomCommand> PreLinkCommands;
- std::vector<cmCustomCommand> PostBuildCommands;
- std::vector<std::pair<TLLSignature, cmListFileContext>> TLLCommands;
- LinkLibraryVectorType OriginalLinkLibraries;
- cmMakefile* Makefile;
- cmTargetInternalPointer Internal;
- cmStateEnums::TargetType TargetTypeValue;
- bool HaveInstallRule;
- bool DLLPlatform;
- bool IsAndroid;
- bool IsImportedTarget;
- bool ImportedGloballyVisible;
- bool BuildInterfaceIncludesAppended;
-
- std::string ProcessSourceItemCMP0049(const std::string& s);
-
- /** Return whether or not the target has a DLL import library. */
- bool HasImportLibrary() const;
-
- // Internal representation details.
- friend class cmTargetInternals;
- friend class cmGeneratorTarget;
- friend class cmTargetTraceDependencies;
-
- cmListFileBacktrace Backtrace;
+ std::unique_ptr<cmTargetInternals> impl;
};
-typedef std::unordered_map<std::string, cmTarget> cmTargets;
-
#endif
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index d2c3496ed..3f763afaf 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -63,10 +63,13 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty(
builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
builtIns.insert("COMPATIBLE_INTERFACE_STRING");
builtIns.insert("EXPORT_NAME");
+ builtIns.insert("EXPORT_PROPERTIES");
builtIns.insert("IMPORTED");
builtIns.insert("IMPORTED_GLOBAL");
builtIns.insert("MANUALLY_ADDED_DEPENDENCIES");
builtIns.insert("NAME");
+ builtIns.insert("PRIVATE_HEADER");
+ builtIns.insert("PUBLIC_HEADER");
builtIns.insert("TYPE");
}
diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h
index 97e4fba2c..efbf95f7f 100644
--- a/Source/cmTargetPropertyComputer.h
+++ b/Source/cmTargetPropertyComputer.h
@@ -81,7 +81,7 @@ private:
context)) {
return nullptr;
}
- const char* configName = prop.c_str() + 9;
+ std::string configName = prop.substr(9);
return ComputeLocation(tgt, configName);
}
diff --git a/Source/cmTest.h b/Source/cmTest.h
index d4839d171..88dc73089 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -26,14 +26,14 @@ public:
cmTest(cmMakefile* mf);
~cmTest();
- ///! Set the test name
+ //! Set the test name
void SetName(const std::string& name);
std::string GetName() const { return this->Name; }
void SetCommand(std::vector<std::string> const& command);
std::vector<std::string> const& GetCommand() const { return this->Command; }
- ///! Set/Get a property of this source file
+ //! Set/Get a property of this source file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 5102613eb..571cd0909 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmOutputConverter.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTest.h"
@@ -94,10 +95,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
std::string emulatorExe(emulatorWithArgs[0]);
cmSystemTools::ConvertToUnixSlashes(emulatorExe);
os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
- for (std::vector<std::string>::const_iterator ei =
- emulatorWithArgs.begin() + 1;
- ei != emulatorWithArgs.end(); ++ei) {
- os << cmOutputConverter::EscapeForCMake(*ei) << " ";
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
+ os << cmOutputConverter::EscapeForCMake(arg) << " ";
}
}
} else {
@@ -108,11 +107,10 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
// Generate the command line with full escapes.
os << cmOutputConverter::EscapeForCMake(exe);
- for (std::vector<std::string>::const_iterator ci = command.begin() + 1;
- ci != command.end(); ++ci) {
+ for (std::string const& arg : cmMakeRange(command).advance(1)) {
os << " "
<< cmOutputConverter::EscapeForCMake(
- ge.Parse(*ci)->Evaluate(this->LG, config));
+ ge.Parse(arg)->Evaluate(this->LG, config));
}
// Finish the test command.
@@ -157,12 +155,11 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
fout << "add_test(";
fout << this->Test->GetName() << " \"" << exe << "\"";
- for (std::vector<std::string>::const_iterator argit = command.begin() + 1;
- argit != command.end(); ++argit) {
+ for (std::string const& arg : cmMakeRange(command).advance(1)) {
// Just double-quote all arguments so they are re-parsed
// correctly by the test system.
fout << " \"";
- for (char c : *argit) {
+ for (char c : arg) {
// Escape quotes within arguments. We should escape
// backslashes too but we cannot because it makes the result
// inconsistent with previous behavior of this command.
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index c57aabdc3..a92c2a05c 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -8,6 +8,7 @@
#include "cmDuration.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
@@ -145,7 +146,7 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
const char* compileOutput =
this->Makefile->GetDefinition(this->OutputVariable);
if (compileOutput) {
- runOutputContents = std::string(compileOutput) + runOutputContents;
+ runOutputContents = compileOutput + runOutputContents;
}
this->Makefile->AddDefinition(this->OutputVariable,
runOutputContents.c_str());
@@ -166,31 +167,28 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
int retVal = -1;
std::string finalCommand;
- const std::string emulator =
+ const std::string& emulator =
this->Makefile->GetSafeDefinition("CMAKE_CROSSCOMPILING_EMULATOR");
if (!emulator.empty()) {
std::vector<std::string> emulatorWithArgs;
cmSystemTools::ExpandListArgument(emulator, emulatorWithArgs);
finalCommand +=
- cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0].c_str());
+ cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]);
finalCommand += " ";
- for (std::vector<std::string>::const_iterator ei =
- emulatorWithArgs.begin() + 1;
- ei != emulatorWithArgs.end(); ++ei) {
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
finalCommand += "\"";
- finalCommand += *ei;
+ finalCommand += arg;
finalCommand += "\"";
finalCommand += " ";
}
}
- finalCommand +=
- cmSystemTools::ConvertToRunCommandPath(this->OutputFile.c_str());
+ finalCommand += cmSystemTools::ConvertToRunCommandPath(this->OutputFile);
if (!runArgs.empty()) {
finalCommand += runArgs;
}
bool worked = cmSystemTools::RunSingleCommand(
- finalCommand.c_str(), out, out, &retVal, nullptr,
- cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ finalCommand, out, out, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
+ cmDuration::zero());
// set the run var
char retChar[16];
const char* retStr;
@@ -235,7 +233,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
this->RunResultVariable + "__TRYRUN_OUTPUT";
bool error = false;
- if (this->Makefile->GetDefinition(this->RunResultVariable) == nullptr) {
+ if (!this->Makefile->GetDefinition(this->RunResultVariable)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
std::string comment;
@@ -257,8 +255,8 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
}
// is the output from the executable used ?
- if (out != nullptr) {
- if (this->Makefile->GetDefinition(internalRunOutputName) == nullptr) {
+ if (out) {
+ if (!this->Makefile->GetDefinition(internalRunOutputName)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
std::string comment;
@@ -306,7 +304,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
comment += " to\n"
" the exit code (in many cases 0 for success), otherwise "
"enter \"FAILED_TO_RUN\".\n";
- if (out != nullptr) {
+ if (out) {
comment += internalRunOutputName;
comment +=
"\n contains the text the executable "
@@ -337,7 +335,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
<< this->Makefile->GetDefinition(this->RunResultVariable)
<< "\"\n CACHE STRING \"Result from TRY_RUN\" FORCE)\n\n";
- if (out != nullptr) {
+ if (out) {
file << "set( " << internalRunOutputName << " \n \""
<< this->Makefile->GetDefinition(internalRunOutputName)
<< "\"\n CACHE STRING \"Output from TRY_RUN\" FORCE)\n\n";
@@ -350,7 +348,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
"please set the following cache variables "
"appropriately:\n";
errorMessage += " " + this->RunResultVariable + " (advanced)\n";
- if (out != nullptr) {
+ if (out) {
errorMessage += " " + internalRunOutputName + " (advanced)\n";
}
errorMessage += detailsString;
@@ -358,7 +356,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
return;
}
- if (out != nullptr) {
+ if (out) {
(*out) = this->Makefile->GetDefinition(internalRunOutputName);
}
}
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx
index fd07d2dba..db674636c 100644
--- a/Source/cmUVHandlePtr.cxx
+++ b/Source/cmUVHandlePtr.cxx
@@ -11,19 +11,59 @@
namespace cm {
-static void close_delete(uv_handle_t* h)
+struct uv_loop_deleter
{
- free(h);
+ void operator()(uv_loop_t* loop) const;
+};
+
+void uv_loop_deleter::operator()(uv_loop_t* loop) const
+{
+ uv_run(loop, UV_RUN_DEFAULT);
+ int result = uv_loop_close(loop);
+ (void)result;
+ assert(result >= 0);
+ free(loop);
+}
+
+int uv_loop_ptr::init(void* data)
+{
+ this->reset();
+
+ this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))),
+ uv_loop_deleter());
+ this->loop->data = data;
+
+ return uv_loop_init(this->loop.get());
+}
+
+void uv_loop_ptr::reset()
+{
+ this->loop.reset();
+}
+
+uv_loop_ptr::operator uv_loop_t*()
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::operator->() const noexcept
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::get() const
+{
+ return this->loop.get();
}
template <typename T>
-static void default_delete(T* type_handle)
+static void handle_default_delete(T* type_handle)
{
auto handle = reinterpret_cast<uv_handle_t*>(type_handle);
if (handle) {
assert(!uv_is_closing(handle));
if (!uv_is_closing(handle)) {
- uv_close(handle, &close_delete);
+ uv_close(handle, [](uv_handle_t* h) { free(h); });
}
}
}
@@ -34,7 +74,7 @@ static void default_delete(T* type_handle)
template <typename T>
struct uv_handle_deleter
{
- void operator()(T* type_handle) const { default_delete(type_handle); }
+ void operator()(T* type_handle) const { handle_default_delete(type_handle); }
};
template <typename T>
@@ -107,7 +147,7 @@ struct uv_handle_deleter<uv_async_t>
void operator()(uv_async_t* handle)
{
std::lock_guard<std::mutex> lock(*handleMutex);
- default_delete(handle);
+ handle_default_delete(handle);
}
};
@@ -136,7 +176,7 @@ struct uv_handle_deleter<uv_signal_t>
{
if (handle) {
uv_signal_stop(handle);
- default_delete(handle);
+ handle_default_delete(handle);
}
}
};
@@ -171,7 +211,6 @@ uv_pipe_ptr::operator uv_stream_t*() const
return reinterpret_cast<uv_stream_t*>(handle.get());
}
-#ifdef CMAKE_BUILD_WITH_CMAKE
int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
void* data)
{
@@ -191,6 +230,7 @@ int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
return uv_timer_start(*this, cb, timeout, repeat);
}
+#ifdef CMAKE_BUILD_WITH_CMAKE
uv_tty_ptr::operator uv_stream_t*() const
{
return reinterpret_cast<uv_stream_t*>(handle.get());
@@ -215,13 +255,13 @@ UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream)
-#ifdef CMAKE_BUILD_WITH_CMAKE
-UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
-
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer)
+#ifdef CMAKE_BUILD_WITH_CMAKE
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
+
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty)
#endif
}
diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h
index 992c429b1..c09e4bfdf 100644
--- a/Source/cmUVHandlePtr.h
+++ b/Source/cmUVHandlePtr.h
@@ -30,7 +30,45 @@
namespace cm {
/***
- * RAII class to simplify and insure the safe usage of uv_*_t types. This
+ * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes
+ * making sure resources are properly freed.
+ */
+class uv_loop_ptr
+{
+protected:
+ std::shared_ptr<uv_loop_t> loop;
+
+public:
+ uv_loop_ptr(uv_loop_ptr const&) = delete;
+ uv_loop_ptr& operator=(uv_loop_ptr const&) = delete;
+ uv_loop_ptr(uv_loop_ptr&&) noexcept;
+ uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept;
+
+ // Dtor and ctor need to be inline defined like this for default ctors and
+ // dtors to work. Some compilers do not like '= default' here.
+ uv_loop_ptr() {} // NOLINT(modernize-use-equals-default)
+ uv_loop_ptr(std::nullptr_t) {}
+ ~uv_loop_ptr() { this->reset(); }
+
+ int init(void* data = nullptr);
+
+ /**
+ * Properly close the handle if needed and sets the inner handle to nullptr
+ */
+ void reset();
+
+ /**
+ * Allow less verbose calling of uv_loop_* functions
+ * @return reinterpreted handle
+ */
+ operator uv_loop_t*();
+
+ uv_loop_t* get() const;
+ uv_loop_t* operator->() const noexcept;
+};
+
+/***
+ * RAII class to simplify and ensure the safe usage of uv_*_t types. This
* includes making sure resources are properly freed and contains casting
* operators which allow for passing into relevant uv_* functions.
*
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
new file mode 100644
index 000000000..90ece0bc5
--- /dev/null
+++ b/Source/cmUVProcessChain.cxx
@@ -0,0 +1,395 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUVProcessChain.h"
+
+#include "cmAlgorithms.h"
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+#include "cm_uv.h"
+
+#include <assert.h>
+
+#include <iterator>
+#include <memory>
+#include <utility>
+
+struct cmUVProcessChain::InternalData
+{
+ struct BasicStreamData
+ {
+ cmUVStreambuf Streambuf;
+ cm::uv_pipe_ptr BuiltinStream;
+ uv_stdio_container_t Stdio;
+ };
+
+ template <typename IOStream>
+ struct StreamData : public BasicStreamData
+ {
+ StreamData()
+ : BuiltinIOStream(&this->Streambuf)
+ {
+ }
+
+ IOStream BuiltinIOStream;
+
+ IOStream* GetBuiltinStream()
+ {
+ if (this->BuiltinStream.get()) {
+ return &this->BuiltinIOStream;
+ }
+ return nullptr;
+ }
+ };
+
+ struct ProcessData
+ {
+ cmUVProcessChain::InternalData* Data;
+ cm::uv_process_ptr Process;
+ cm::uv_pipe_ptr OutputPipe;
+ bool Finished = false;
+ Status ProcessStatus;
+ };
+
+ const cmUVProcessChainBuilder* Builder = nullptr;
+
+ bool Valid = false;
+
+ cm::uv_loop_ptr Loop;
+
+ StreamData<std::istream> OutputStreamData;
+ StreamData<std::istream> ErrorStreamData;
+
+ unsigned int ProcessesCompleted = 0;
+ std::vector<std::unique_ptr<ProcessData>> Processes;
+
+ bool Prepare(const cmUVProcessChainBuilder* builder);
+ bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config,
+ bool first, bool last);
+ bool Finish();
+
+ static const Status* GetStatus(const ProcessData& data);
+};
+
+cmUVProcessChainBuilder::cmUVProcessChainBuilder()
+{
+ this->SetNoStream(Stream_INPUT)
+ .SetNoStream(Stream_OUTPUT)
+ .SetNoStream(Stream_ERROR);
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
+ const std::vector<std::string>& arguments)
+{
+ if (!arguments.empty()) {
+ this->Processes.emplace_back();
+ this->Processes.back().Arguments = arguments;
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = None;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream(
+ Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = Builtin;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
+ Stream stdio, int fd)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = External;
+ streamData.FileDescriptor = fd;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChain cmUVProcessChainBuilder::Start() const
+{
+ cmUVProcessChain chain;
+
+ if (!chain.Data->Prepare(this)) {
+ return chain;
+ }
+
+ for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) {
+ if (!chain.Data->AddCommand(*it, it == this->Processes.begin(),
+ it == std::prev(this->Processes.end()))) {
+ return chain;
+ }
+ }
+
+ chain.Data->Finish();
+
+ return chain;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus(
+ const cmUVProcessChain::InternalData::ProcessData& data)
+{
+ if (data.Finished) {
+ return &data.ProcessStatus;
+ }
+ return nullptr;
+}
+
+bool cmUVProcessChain::InternalData::Prepare(
+ const cmUVProcessChainBuilder* builder)
+{
+ this->Builder = builder;
+
+ auto const& output =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
+ auto& outputData = this->OutputStreamData;
+ switch (output.Type) {
+ case cmUVProcessChainBuilder::None:
+ outputData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin:
+ outputData.BuiltinStream.init(*this->Loop, 0);
+ outputData.Stdio.flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ outputData.Stdio.data.stream = outputData.BuiltinStream;
+ break;
+
+ case cmUVProcessChainBuilder::External:
+ outputData.Stdio.flags = UV_INHERIT_FD;
+ outputData.Stdio.data.fd = output.FileDescriptor;
+ break;
+ }
+
+ auto const& error =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
+ auto& errorData = this->ErrorStreamData;
+ switch (error.Type) {
+ case cmUVProcessChainBuilder::None:
+ errorData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin: {
+ int pipeFd[2];
+ if (cmGetPipes(pipeFd) < 0) {
+ return false;
+ }
+
+ errorData.BuiltinStream.init(*this->Loop, 0);
+ if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
+ return false;
+ }
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = pipeFd[1];
+ break;
+ }
+
+ case cmUVProcessChainBuilder::External:
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = error.FileDescriptor;
+ break;
+ }
+
+ return true;
+}
+
+bool cmUVProcessChain::InternalData::AddCommand(
+ const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
+ bool last)
+{
+ this->Processes.emplace_back(cm::make_unique<ProcessData>());
+ auto& process = *this->Processes.back();
+ process.Data = this;
+
+ auto options = uv_process_options_t();
+
+ // Bounds were checked at add time, first element is guaranteed to exist
+ options.file = config.Arguments[0].c_str();
+
+ std::vector<const char*> arguments;
+ for (auto const& arg : config.Arguments) {
+ arguments.push_back(arg.c_str());
+ }
+ arguments.push_back(nullptr);
+ options.args = const_cast<char**>(arguments.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+
+ std::array<uv_stdio_container_t, 3> stdio;
+ stdio[0] = uv_stdio_container_t();
+ if (first) {
+ stdio[0].flags = UV_IGNORE;
+ } else {
+ assert(this->Processes.size() >= 2);
+ auto& prev = *this->Processes[this->Processes.size() - 2];
+ stdio[0].flags = UV_INHERIT_STREAM;
+ stdio[0].data.stream = prev.OutputPipe;
+ }
+ if (last) {
+ stdio[1] = this->OutputStreamData.Stdio;
+ } else {
+ if (process.OutputPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ stdio[1] = uv_stdio_container_t();
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = process.OutputPipe;
+ }
+ stdio[2] = this->ErrorStreamData.Stdio;
+
+ options.stdio = stdio.data();
+ options.stdio_count = 3;
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto* processData = static_cast<ProcessData*>(handle->data);
+ processData->Finished = true;
+ processData->ProcessStatus.ExitStatus = exitStatus;
+ processData->ProcessStatus.TermSignal = termSignal;
+ processData->Data->ProcessesCompleted++;
+ };
+
+ return process.Process.spawn(*this->Loop, options, &process) >= 0;
+}
+
+bool cmUVProcessChain::InternalData::Finish()
+{
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ this->OutputStreamData.Streambuf.open(
+ this->OutputStreamData.BuiltinStream);
+ }
+
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ cm::uv_pipe_ptr tmpPipe;
+ if (tmpPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) {
+ return false;
+ }
+ tmpPipe.reset();
+
+ this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream);
+ }
+
+ this->Valid = true;
+ return true;
+}
+
+cmUVProcessChain::cmUVProcessChain()
+ : Data(cm::make_unique<InternalData>())
+{
+ this->Data->Loop.init();
+}
+
+cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept
+ : Data(std::move(other.Data))
+{
+}
+
+cmUVProcessChain::~cmUVProcessChain() = default;
+
+cmUVProcessChain& cmUVProcessChain::operator=(
+ cmUVProcessChain&& other) noexcept
+{
+ this->Data = std::move(other.Data);
+ return *this;
+}
+
+uv_loop_t& cmUVProcessChain::GetLoop()
+{
+ return *this->Data->Loop;
+}
+
+std::istream* cmUVProcessChain::OutputStream()
+{
+ return this->Data->OutputStreamData.GetBuiltinStream();
+}
+
+std::istream* cmUVProcessChain::ErrorStream()
+{
+ return this->Data->ErrorStreamData.GetBuiltinStream();
+}
+
+bool cmUVProcessChain::Valid() const
+{
+ return this->Data->Valid;
+}
+
+bool cmUVProcessChain::Wait(int64_t milliseconds)
+{
+ bool timeout = false;
+ cm::uv_timer_ptr timer;
+
+ if (milliseconds >= 0) {
+ timer.init(*this->Data->Loop, &timeout);
+ timer.start(
+ [](uv_timer_t* handle) {
+ auto* timeoutPtr = static_cast<bool*>(handle->data);
+ *timeoutPtr = true;
+ },
+ milliseconds, 0);
+ }
+
+ while (!timeout &&
+ this->Data->ProcessesCompleted < this->Data->Processes.size()) {
+ uv_run(this->Data->Loop, UV_RUN_ONCE);
+ }
+
+ return !timeout;
+}
+
+std::vector<const cmUVProcessChain::Status*> cmUVProcessChain::GetStatus()
+ const
+{
+ std::vector<const cmUVProcessChain::Status*> statuses(
+ this->Data->Processes.size(), nullptr);
+ for (std::size_t i = 0; i < statuses.size(); i++) {
+ statuses[i] = this->GetStatus(i);
+ }
+ return statuses;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::GetStatus(
+ std::size_t index) const
+{
+ auto const& process = *this->Data->Processes[index];
+ if (process.Finished) {
+ return &process.ProcessStatus;
+ }
+ return nullptr;
+}
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
new file mode 100644
index 000000000..2b3352070
--- /dev/null
+++ b/Source/cmUVProcessChain.h
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVProcessChain_h
+#define cmUVProcessChain_h
+
+#include "cm_uv.h"
+
+#include <array>
+#include <iosfwd>
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+
+class cmUVProcessChain;
+
+class cmUVProcessChainBuilder
+{
+public:
+ enum Stream
+ {
+ Stream_INPUT = 0,
+ Stream_OUTPUT = 1,
+ Stream_ERROR = 2,
+ };
+
+ cmUVProcessChainBuilder();
+
+ cmUVProcessChainBuilder& AddCommand(
+ const std::vector<std::string>& arguments);
+ cmUVProcessChainBuilder& SetNoStream(Stream stdio);
+ cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio);
+ cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
+
+ cmUVProcessChain Start() const;
+
+private:
+ enum StdioType
+ {
+ None,
+ Builtin,
+ External,
+ };
+
+ friend class cmUVProcessChain;
+
+ struct StdioConfiguration
+ {
+ StdioType Type;
+ int FileDescriptor;
+ };
+
+ struct ProcessConfiguration
+ {
+ std::vector<std::string> Arguments;
+ };
+
+ std::array<StdioConfiguration, 3> Stdio;
+ std::vector<ProcessConfiguration> Processes;
+};
+
+class cmUVProcessChain
+{
+public:
+ struct Status
+ {
+ int64_t ExitStatus;
+ int TermSignal;
+ };
+
+ cmUVProcessChain(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain(cmUVProcessChain&& other) noexcept;
+
+ ~cmUVProcessChain();
+
+ cmUVProcessChain& operator=(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain& operator=(cmUVProcessChain&& other) noexcept;
+
+ uv_loop_t& GetLoop();
+
+ // FIXME: Add stdin support
+ std::istream* OutputStream();
+ std::istream* ErrorStream();
+
+ bool Valid() const;
+ bool Wait(int64_t milliseconds = -1);
+ std::vector<const Status*> GetStatus() const;
+ const Status* GetStatus(std::size_t index) const;
+
+private:
+ friend class cmUVProcessChainBuilder;
+
+ cmUVProcessChain();
+
+ struct InternalData;
+ std::unique_ptr<InternalData> Data;
+};
+
+#endif
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
new file mode 100644
index 000000000..873352b1a
--- /dev/null
+++ b/Source/cmUVStreambuf.h
@@ -0,0 +1,219 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVStreambuf_h
+#define cmUVStreambuf_h
+
+#include "cmUVHandlePtr.h"
+
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <cstring>
+#include <streambuf>
+#include <vector>
+
+/*
+ * This file is based on example code from:
+ *
+ * http://www.voidcn.com/article/p-vjnlygmc-gy.html
+ *
+ * The example code was distributed under the following license:
+ *
+ * Copyright 2007 Edd Dawson.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+ cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
+ ~cmBasicUVStreambuf() override;
+
+ bool is_open() const;
+
+ cmBasicUVStreambuf* open(uv_stream_t* stream);
+
+ cmBasicUVStreambuf* close();
+
+protected:
+ typename cmBasicUVStreambuf::int_type underflow() override;
+ std::streamsize showmanyc() override;
+
+ // FIXME: Add write support
+
+private:
+ uv_stream_t* Stream = nullptr;
+ void* OldStreamData = nullptr;
+ const std::size_t PutBack = 0;
+ std::vector<CharT> InputBuffer;
+ bool EndOfFile = false;
+
+ void StreamReadStartStop();
+
+ void StreamRead(ssize_t nread);
+ void HandleAlloc(uv_buf_t* buf);
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
+ std::size_t putBack)
+ : PutBack(std::max<std::size_t>(putBack, 1))
+ , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
+{
+ return this->Stream != nullptr;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
+ uv_stream_t* stream)
+{
+ this->close();
+ this->Stream = stream;
+ this->EndOfFile = false;
+ if (this->Stream) {
+ this->OldStreamData = this->Stream->data;
+ this->Stream->data = this;
+ }
+ this->StreamReadStartStop();
+ return this;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ this->Stream->data = this->OldStreamData;
+ }
+ this->Stream = nullptr;
+ CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
+ this->setg(readEnd, readEnd, readEnd);
+ return this;
+}
+
+template <typename CharT, typename Traits>
+typename cmBasicUVStreambuf<CharT, Traits>::int_type
+cmBasicUVStreambuf<CharT, Traits>::underflow()
+{
+ if (!this->is_open()) {
+ return Traits::eof();
+ }
+
+ if (this->gptr() < this->egptr()) {
+ return Traits::to_int_type(*this->gptr());
+ }
+
+ this->StreamReadStartStop();
+ while (this->in_avail() == 0) {
+ uv_run(this->Stream->loop, UV_RUN_ONCE);
+ }
+ if (this->in_avail() == -1) {
+ return Traits::eof();
+ }
+ return Traits::to_int_type(*this->gptr());
+}
+
+template <typename CharT, typename Traits>
+std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
+{
+ if (!this->is_open() || this->EndOfFile) {
+ return -1;
+ }
+ return 0;
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ if (this->gptr() >= this->egptr()) {
+ uv_read_start(
+ this->Stream,
+ [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
+ streambuf->HandleAlloc(buf);
+ },
+ [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
+ streambuf->StreamRead(nread);
+ });
+ }
+ }
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
+{
+ auto size = this->egptr() - this->gptr();
+ std::memmove(this->InputBuffer.data(), this->gptr(),
+ this->egptr() - this->gptr());
+ this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
+ this->InputBuffer.data() + size);
+ buf->base = this->egptr();
+#ifdef _WIN32
+# define BUF_LEN_TYPE ULONG
+#else
+# define BUF_LEN_TYPE size_t
+#endif
+ buf->len = BUF_LEN_TYPE(
+ (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
+ sizeof(CharT));
+#undef BUF_LEN_TYPE
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
+{
+ if (nread > 0) {
+ this->setg(this->eback(), this->gptr(),
+ this->egptr() + nread / sizeof(CharT));
+ uv_read_stop(this->Stream);
+ } else if (nread < 0 /*|| nread == UV_EOF*/) {
+ this->EndOfFile = true;
+ uv_read_stop(this->Stream);
+ }
+}
+
+using cmUVStreambuf = cmBasicUVStreambuf<char>;
+
+#endif
diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx
index 9648b21d8..43581947c 100644
--- a/Source/cmUseMangledMesaCommand.cxx
+++ b/Source/cmUseMangledMesaCommand.cxx
@@ -19,7 +19,7 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- const char* inputDir = args[0].c_str();
+ const std::string& inputDir = args[0];
std::string glh = inputDir;
glh += "/";
glh += "gl.h";
@@ -30,11 +30,11 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
this->SetError(e);
return false;
}
- const char* destDir = args[1].c_str();
+ const std::string& destDir = args[1];
std::vector<std::string> files;
cmSystemTools::Glob(inputDir, "\\.h$", files);
if (files.empty()) {
- cmSystemTools::Error("Could not open Mesa Directory ", inputDir);
+ cmSystemTools::Error("Could not open Mesa Directory " + inputDir);
return false;
}
cmSystemTools::MakeDirectory(destDir);
@@ -42,14 +42,14 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
std::string path = inputDir;
path += "/";
path += f;
- this->CopyAndFullPathMesaHeader(path.c_str(), destDir);
+ this->CopyAndFullPathMesaHeader(path, destDir);
}
return true;
}
-void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
- const char* outdir)
+void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(
+ const std::string& source, const std::string& outdir)
{
std::string dir, file;
cmSystemTools::SplitProgramPath(source, dir, file);
@@ -60,14 +60,14 @@ void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
tempOutputFile += ".tmp";
cmsys::ofstream fout(tempOutputFile.c_str());
if (!fout) {
- cmSystemTools::Error("Could not open file for write in copy operation: ",
- tempOutputFile.c_str(), outdir);
+ cmSystemTools::Error("Could not open file for write in copy operation: " +
+ tempOutputFile + outdir);
cmSystemTools::ReportLastSystemError("");
return;
}
- cmsys::ifstream fin(source);
+ cmsys::ifstream fin(source.c_str());
if (!fin) {
- cmSystemTools::Error("Could not open file for read in copy operation",
+ cmSystemTools::Error("Could not open file for read in copy operation" +
source);
return;
}
@@ -78,7 +78,7 @@ void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
cmsys::RegularExpression includeLine(
"^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
// regular expression for gl/ or GL/ in a file (match(1) of above)
- cmsys::RegularExpression glDirLine("(gl|GL)(/|\\\\)([^<\"]+)");
+ cmsys::RegularExpression glDirLine(R"((gl|GL)(/|\\)([^<"]+))");
// regular expression for gl GL or xmesa in a file (match(1) of above)
cmsys::RegularExpression glLine("(gl|GL|xmesa)");
while (cmSystemTools::GetLineFromStream(fin, inLine)) {
diff --git a/Source/cmUseMangledMesaCommand.h b/Source/cmUseMangledMesaCommand.h
index 78f86167b..e2f1d9b90 100644
--- a/Source/cmUseMangledMesaCommand.h
+++ b/Source/cmUseMangledMesaCommand.h
@@ -20,7 +20,8 @@ public:
cmExecutionStatus& status) override;
protected:
- void CopyAndFullPathMesaHeader(const char* source, const char* outdir);
+ void CopyAndFullPathMesaHeader(const std::string& source,
+ const std::string& outdir);
};
#endif
diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx
index 231bca41d..b59a587cd 100644
--- a/Source/cmUtilitySourceCommand.cxx
+++ b/Source/cmUtilitySourceCommand.cxx
@@ -79,7 +79,7 @@ bool cmUtilitySourceCommand::InitialPass(std::vector<std::string> const& args,
}
// The source exists.
- std::string cmakeCFGout =
+ const std::string& cmakeCFGout =
this->Makefile->GetRequiredDefinition("CMAKE_CFG_INTDIR");
std::string utilityDirectory = this->Makefile->GetCurrentBinaryDirectory();
std::string exePath;
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index 201e1ccef..51ecbd180 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -4,16 +4,10 @@
#include "cmCryptoHash.h"
+#include <array>
#include <string.h>
-cmUuid::cmUuid()
-{
- Groups.push_back(4);
- Groups.push_back(2);
- Groups.push_back(2);
- Groups.push_back(2);
- Groups.push_back(6);
-}
+static const std::array<int, 5> kUuidGroups = { { 4, 2, 2, 2, 6 } };
std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
std::string const& name) const
@@ -83,11 +77,11 @@ bool cmUuid::StringToBinary(std::string const& input,
return false;
}
size_t index = 0;
- for (size_t i = 0; i < this->Groups.size(); ++i) {
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
if (i != 0 && input[index++] != '-') {
return false;
}
- size_t digits = this->Groups[i] * 2;
+ size_t digits = kUuidGroups[i] * 2;
if (!StringToBinaryImpl(input.substr(index, digits), output)) {
return false;
}
@@ -103,12 +97,12 @@ std::string cmUuid::BinaryToString(const unsigned char* input) const
std::string output;
size_t inputIndex = 0;
- for (size_t i = 0; i < this->Groups.size(); ++i) {
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
if (i != 0) {
output += '-';
}
- size_t bytes = this->Groups[i];
+ size_t bytes = kUuidGroups[i];
for (size_t j = 0; j < bytes; ++j) {
unsigned char byte = input[inputIndex++];
output += this->ByteToHex(byte);
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
index 158ce6ee4..7de20dd29 100644
--- a/Source/cmUuid.h
+++ b/Source/cmUuid.h
@@ -15,8 +15,6 @@
class cmUuid
{
public:
- cmUuid();
-
std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
std::string const& name) const;
@@ -42,8 +40,6 @@ private:
std::string BinaryToString(const unsigned char* input) const;
bool IntFromHexDigit(char input, char& output) const;
-
- std::vector<int> Groups;
};
#endif
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
index 5855fed29..123010179 100644
--- a/Source/cmVariableWatch.h
+++ b/Source/cmVariableWatch.h
@@ -72,6 +72,9 @@ protected:
this->DeleteDataCall(this->ClientData);
}
}
+ Pair() = default;
+ Pair(const Pair&) = delete;
+ Pair& operator=(const Pair&) = delete;
};
typedef std::vector<std::shared_ptr<Pair>> VectorOfPairs;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f2f5e3f63..ee5f9b4d0 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -4,11 +4,13 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio10Generator.h"
+#include "cmLinkLineDeviceComputer.h"
#include "cmLocalVisualStudio10Generator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
@@ -624,8 +626,8 @@ void cmVisualStudio10TargetGenerator::Generate()
propsLocal += this->DefaultArtifactDir;
propsLocal += "\\nasm.props";
ConvertToWindowsSlash(propsLocal);
- this->Makefile->ConfigureFile(propsTemplate.c_str(),
- propsLocal.c_str(), false, true, true);
+ this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
+ true);
Elem(e1, "Import").Attribute("Project", propsLocal);
}
}
@@ -663,6 +665,8 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteCustomCommands(e0);
this->WriteAllSources(e0);
this->WriteDotNetReferences(e0);
+ this->WritePackageReferences(e0);
+ this->WriteImports(e0);
this->WriteEmbeddedResourceGroup(e0);
this->WriteXamlFilesGroup(e0);
this->WriteWinRTReferences(e0);
@@ -735,6 +739,33 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteGroups();
}
+void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
+{
+ std::vector<std::string> packageReferences;
+ if (const char* vsPackageReferences =
+ this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) {
+ cmSystemTools::ExpandListArgument(vsPackageReferences, packageReferences);
+ }
+ if (!packageReferences.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (std::string const& ri : packageReferences) {
+ size_t versionIndex = ri.find_last_of('_');
+ if (versionIndex != std::string::npos) {
+ WritePackageReference(e1, ri.substr(0, versionIndex),
+ ri.substr(versionIndex + 1));
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WritePackageReference(
+ Elem& e1, std::string const& ref, std::string const& version)
+{
+ Elem e2(e1, "PackageReference");
+ e2.Attribute("Include", ref);
+ e2.Attribute("Version", version);
+}
+
void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
{
std::vector<std::string> references;
@@ -811,6 +842,24 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference(
this->WriteDotNetReferenceCustomTags(e2, ref);
}
+void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0)
+{
+ const char* imports =
+ this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT");
+ if (imports) {
+ std::vector<std::string> argsSplit;
+ cmSystemTools::ExpandListArgument(std::string(imports), argsSplit, false);
+ for (auto& path : argsSplit) {
+ if (!cmsys::SystemTools::FileIsFullPath(path)) {
+ path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
+ }
+ ConvertToWindowsSlash(path);
+ Elem e1(e0, "Import");
+ e1.Attribute("Project", path);
+ }
+ }
+}
+
void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
Elem& e2, std::string const& ref)
{
@@ -1164,7 +1213,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
e1.Element("CharacterSet", "Unicode");
} else if (this->GeneratorTarget->GetType() <=
- cmStateEnums::MODULE_LIBRARY &&
+ cmStateEnums::OBJECT_LIBRARY &&
this->ClOptions[config]->UsingSBCS()) {
e1.Element("CharacterSet", "NotSet");
} else {
@@ -1323,8 +1372,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
std::string error = "Could not create file: [";
error += sourcePath;
error += "] ";
- cmSystemTools::Error(error.c_str(),
- cmSystemTools::GetLastSystemError().c_str());
+ cmSystemTools::Error(error + cmSystemTools::GetLastSystemError());
}
}
}
@@ -1454,10 +1502,10 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath(
static void ConvertToWindowsSlash(std::string& s)
{
// first convert all of the slashes
- std::string::size_type pos = 0;
- while ((pos = s.find('/', pos)) != std::string::npos) {
- s[pos] = '\\';
- pos++;
+ for (auto& ch : s) {
+ if (ch == '/') {
+ ch = '\\';
+ }
}
}
@@ -1473,7 +1521,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
this->GeneratorTarget->GetAllConfigSources();
- std::set<cmSourceGroup*> groupsUsed;
+ std::set<cmSourceGroup const*> groupsUsed;
for (cmGeneratorTarget::AllConfigSource const& si : sources) {
std::string const& source = si.Source->GetFullPath();
cmSourceGroup* sourceGroup =
@@ -1558,13 +1606,13 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
{
Elem e1(e0, "ItemGroup");
e1.SetHasElements();
- std::vector<cmSourceGroup*> groupsVec(groupsUsed.begin(),
- groupsUsed.end());
+ std::vector<cmSourceGroup const*> groupsVec(groupsUsed.begin(),
+ groupsUsed.end());
std::sort(groupsVec.begin(), groupsVec.end(),
- [](cmSourceGroup* l, cmSourceGroup* r) {
+ [](cmSourceGroup const* l, cmSourceGroup const* r) {
return l->GetFullName() < r->GetFullName();
});
- for (cmSourceGroup* sg : groupsVec) {
+ for (cmSourceGroup const* sg : groupsVec) {
std::string const& name = sg->GetFullName();
if (!name.empty()) {
std::string guidName = "SG_Filter_" + name;
@@ -1596,7 +1644,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// Add to groupsUsed empty source groups that have non-empty children.
void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
- std::set<cmSourceGroup*>& groupsUsed,
+ std::set<cmSourceGroup const*>& groupsUsed,
const std::vector<cmSourceGroup>& allGroups)
{
for (cmSourceGroup const& current : allGroups) {
@@ -1607,17 +1655,15 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
this->AddMissingSourceGroups(groupsUsed, children);
- cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&current);
- if (groupsUsed.find(current_ptr) != groupsUsed.end()) {
+ if (groupsUsed.count(&current) > 0) {
continue; // group has already been added to set
}
// check if it least one of the group's descendants is not empty
// (at least one child must already have been added)
- std::vector<cmSourceGroup>::const_iterator child_it = children.begin();
+ auto child_it = children.begin();
while (child_it != children.end()) {
- cmSourceGroup* child_ptr = const_cast<cmSourceGroup*>(&(*child_it));
- if (groupsUsed.find(child_ptr) != groupsUsed.end()) {
+ if (groupsUsed.count(&(*child_it)) > 0) {
break; // found a child that was already added => add current group too
}
child_it++;
@@ -1627,7 +1673,7 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
continue; // no descendants have source files => ignore this group
}
- groupsUsed.insert(current_ptr);
+ groupsUsed.insert(&current);
}
}
@@ -2539,8 +2585,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->GeneratorTarget->GetLinkerLanguage(configName);
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Name.c_str());
+ "CMake can not determine linker language for target: " + this->Name);
return false;
}
@@ -2555,24 +2600,17 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
} else {
std::set<std::string> languages;
this->GeneratorTarget->GetLanguages(languages, configName);
- for (const char* const* l = cm::cbegin(clLangs); l != cm::cend(clLangs);
- ++l) {
- if (languages.find(*l) != languages.end()) {
- langForClCompile = *l;
+ for (const char* l : clLangs) {
+ if (languages.count(l)) {
+ langForClCompile = l;
break;
}
}
}
this->LangForClCompile = langForClCompile;
if (!langForClCompile.empty()) {
- std::string baseFlagVar = "CMAKE_";
- baseFlagVar += langForClCompile;
- baseFlagVar += "_FLAGS";
- flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
- std::string flagVar =
- baseFlagVar + "_" + cmSystemTools::UpperCase(configName);
- flags += " ";
- flags += this->Makefile->GetRequiredDefinition(flagVar);
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ langForClCompile, configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
langForClCompile, configName);
}
@@ -2872,10 +2910,9 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
Options& cudaOptions = *pOptions;
// Get compile flags for CUDA in this directory.
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = std::string("CMAKE_CUDA_FLAGS_") + CONFIG;
- std::string flags = this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS") +
- " " + this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA",
+ configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
configName);
@@ -3022,21 +3059,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
Options& cudaLinkOptions = *pOptions;
// Determine if we need to do a device link
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- } else {
- switch (this->GeneratorTarget->GetType()) {
- case cmStateEnums::SHARED_LIBRARY:
- case cmStateEnums::MODULE_LIBRARY:
- case cmStateEnums::EXECUTABLE:
- doDeviceLinking = true;
- break;
- default:
- break;
- }
- }
+ const bool doDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, configName);
cudaLinkOptions.AddFlag("PerformDeviceLink",
doDeviceLinking ? "true" : "false");
@@ -3089,11 +3113,9 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable());
Options& masmOptions = *pOptions;
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = std::string("CMAKE_ASM_MASM_FLAGS_") + CONFIG;
- std::string flags =
- this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS") + " " +
- this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_MASM", configName);
masmOptions.Parse(flags);
@@ -3143,12 +3165,11 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable());
Options& nasmOptions = *pOptions;
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = "CMAKE_ASM_NASM_FLAGS_" + CONFIG;
- std::string flags =
- this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS") + " -f" +
- this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT") + " " +
- this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_NASM", configName);
+ flags += " -f";
+ flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
nasmOptions.Parse(flags);
// Get includes for this target
@@ -3370,8 +3391,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
const std::string& linkLanguage = linkClosure->LinkerLanguage;
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Name.c_str());
+ "CMake can not determine linker language for target: " + this->Name);
return false;
}
@@ -3416,8 +3436,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
this->GeneratorTarget->GetLinkInformation(config);
if (!pcli) {
cmSystemTools::Error(
- "CMake can not compute cmComputeLinkInformation for target: ",
- this->Name.c_str());
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
return false;
}
cmComputeLinkInformation& cli = *pcli;
@@ -3444,7 +3464,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::string standardLibsVar = "CMAKE_";
standardLibsVar += linkLanguage;
standardLibsVar += "_STANDARD_LIBRARIES";
- std::string const libs = this->Makefile->GetSafeDefinition(standardLibsVar);
+ std::string const& libs = this->Makefile->GetSafeDefinition(standardLibsVar);
cmSystemTools::ParseWindowsCommandLine(libs.c_str(), libVec);
linkOptions.AddFlag("AdditionalDependencies", libVec);
@@ -3464,18 +3484,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
linkDirs.push_back("%(AdditionalLibraryDirectories)");
linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs);
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
+ cmGeneratorTarget::Names targetNames;
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
- this->GeneratorTarget->GetExecutableNames(
- targetName, targetNameFull, targetNameImport, targetNamePDB, config);
+ targetNames = this->GeneratorTarget->GetExecutableNames(config);
} else {
- this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
- targetNameFull, targetNameImport,
- targetNamePDB, config);
+ targetNames = this->GeneratorTarget->GetLibraryNames(config);
}
if (this->MSTools) {
@@ -3516,11 +3529,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::string pdb = this->GeneratorTarget->GetPDBDirectory(config);
pdb += "/";
- pdb += targetNamePDB;
+ pdb += targetNames.PDB;
std::string imLib = this->GeneratorTarget->GetDirectory(
config, cmStateEnums::ImportLibraryArtifact);
imLib += "/";
- imLib += targetNameImport;
+ imLib += targetNames.ImportLibrary;
linkOptions.AddFlag("ImportLibrary", imLib);
linkOptions.AddFlag("ProgramDataBaseFile", pdb);
@@ -3544,7 +3557,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib");
}
} else if (this->NsightTegra) {
- linkOptions.AddFlag("SoName", targetNameSO);
+ linkOptions.AddFlag("SoName", targetNames.SharedObject);
}
linkOptions.Parse(flags);
@@ -3604,8 +3617,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLibOptions(
this->GeneratorTarget->GetLinkInformation(config);
if (!pcli) {
cmSystemTools::Error(
- "CMake can not compute cmComputeLinkInformation for target: ",
- this->Name.c_str());
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
return false;
}
@@ -4097,10 +4110,7 @@ bool cmVisualStudio10TargetGenerator::IsResxHeader(
{
std::set<std::string> expectedResxHeaders;
this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, "");
-
- std::set<std::string>::const_iterator it =
- expectedResxHeaders.find(headerFile);
- return it != expectedResxHeaders.end();
+ return expectedResxHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlHeader(
@@ -4108,10 +4118,7 @@ bool cmVisualStudio10TargetGenerator::IsXamlHeader(
{
std::set<std::string> expectedXamlHeaders;
this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, "");
-
- std::set<std::string>::const_iterator it =
- expectedXamlHeaders.find(headerFile);
- return it != expectedXamlHeaders.end();
+ return expectedXamlHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlSource(
@@ -4119,10 +4126,7 @@ bool cmVisualStudio10TargetGenerator::IsXamlSource(
{
std::set<std::string> expectedXamlSources;
this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, "");
-
- std::set<std::string>::const_iterator it =
- expectedXamlSources.find(sourceFile);
- return it != expectedXamlSources.end();
+ return expectedXamlSources.count(sourceFile) > 0;
}
void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
@@ -4131,29 +4135,29 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
bool isAppContainer = false;
bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone();
bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore();
- std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ std::string const& rev = this->GlobalGenerator->GetApplicationTypeRevision();
if (isWindowsPhone || isWindowsStore) {
e1.Element("ApplicationType",
(isWindowsPhone ? "Windows Phone" : "Windows Store"));
e1.Element("DefaultLanguage", "en-US");
- if (cmHasLiteralPrefix(v, "10.0")) {
- e1.Element("ApplicationTypeRevision", "10.0");
+ if (rev == "10.0") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 14.0 is necessary for building 10.0 apps
e1.Element("MinimumVisualStudioVersion", "14.0");
if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
isAppContainer = true;
}
- } else if (v == "8.1") {
- e1.Element("ApplicationTypeRevision", v);
+ } else if (rev == "8.1") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 12.0 is necessary for building 8.1 apps
e1.Element("MinimumVisualStudioVersion", "12.0");
if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
isAppContainer = true;
}
- } else if (v == "8.0") {
- e1.Element("ApplicationTypeRevision", v);
+ } else if (rev == "8.0") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 11.0 is necessary for building 8.0 apps
e1.Element("MinimumVisualStudioVersion", "11.0");
@@ -4185,7 +4189,7 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
"VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION");
if (targetPlatformMinVersion) {
e1.Element("WindowsTargetPlatformMinVersion", targetPlatformMinVersion);
- } else if (isWindowsStore && cmHasLiteralPrefix(v, "10.0")) {
+ } else if (isWindowsStore && rev == "10.0") {
// If the min version is not set, then use the TargetPlatformVersion
if (!targetPlatformVersion.empty()) {
e1.Element("WindowsTargetPlatformMinVersion", targetPlatformVersion);
@@ -4693,10 +4697,8 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties(
Elem& e2, const std::map<std::string, std::string>& tags)
{
- if (!tags.empty()) {
- for (const auto& i : tags) {
- e2.Element(i.first.c_str(), i.second);
- }
+ for (const auto& i : tags) {
+ e2.Element(i.first.c_str(), i.second);
}
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 68db332e1..860b8093e 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -72,10 +72,14 @@ private:
void WriteExcludeFromBuild(Elem& e2,
std::vector<size_t> const& exclude_configs);
void WriteAllSources(Elem& e0);
+ void WritePackageReferences(Elem& e0);
+ void WritePackageReference(Elem& e1, std::string const& ref,
+ std::string const& version);
void WriteDotNetReferences(Elem& e0);
void WriteDotNetReference(Elem& e1, std::string const& ref,
std::string const& hint,
std::string const& config);
+ void WriteImports(Elem& e0);
void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref);
void WriteEmbeddedResourceGroup(Elem& e0);
void WriteWinRTReferences(Elem& e0);
@@ -166,7 +170,7 @@ private:
void WriteGroupSources(Elem& e0, std::string const& name,
ToolSources const& sources,
std::vector<cmSourceGroup>&);
- void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed,
+ void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
const std::vector<cmSourceGroup>& allGroups);
bool IsResxHeader(const std::string& headerFile);
bool IsXamlHeader(const std::string& headerFile);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 5c3e533b8..e1b0c70b6 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -374,19 +374,19 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
{
// Look for Intel Fortran flags that do not map well in the flag table.
if (this->CurrentTool == FortranCompiler) {
- if (flag == "/dbglibs") {
+ if (flag == "/dbglibs" || flag == "-dbglibs") {
this->FortranRuntimeDebug = true;
return;
}
- if (flag == "/threads") {
+ if (flag == "/threads" || flag == "-threads") {
this->FortranRuntimeMT = true;
return;
}
- if (flag == "/libs:dll") {
+ if (flag == "/libs:dll" || flag == "-libs:dll") {
this->FortranRuntimeDLL = true;
return;
}
- if (flag == "/libs:static") {
+ if (flag == "/libs:static" || flag == "-libs:static") {
this->FortranRuntimeDLL = false;
return;
}
@@ -438,14 +438,13 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
const char* sep = "";
std::vector<std::string>::const_iterator de =
cmRemoveDuplicates(this->Defines);
- for (std::vector<std::string>::const_iterator di = this->Defines.begin();
- di != de; ++di) {
+ for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
// Escape the definition for the compiler.
std::string define;
if (this->Version < cmGlobalVisualStudioGenerator::VS10) {
- define = this->LocalGenerator->EscapeForShell(*di, true);
+ define = this->LocalGenerator->EscapeForShell(di, true);
} else {
- define = *di;
+ define = di;
}
// Escape this flag for the MSBuild.
if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
new file mode 100644
index 000000000..cbf070e91
--- /dev/null
+++ b/Source/cmWorkerPool.cxx
@@ -0,0 +1,763 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWorkerPool.h"
+
+#include "cmRange.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <stddef.h>
+#include <thread>
+
+/**
+ * @brief libuv pipe buffer class
+ */
+class cmUVPipeBuffer
+{
+public:
+ typedef cmRange<char const*> DataRange;
+ typedef std::function<void(DataRange)> DataFunction;
+ /// On error the ssize_t argument is a non zero libuv error code
+ typedef std::function<void(ssize_t)> EndFunction;
+
+public:
+ /**
+ * Reset to construction state
+ */
+ void reset();
+
+ /**
+ * Initializes uv_pipe(), uv_stream() and uv_handle()
+ * @return true on success
+ */
+ bool init(uv_loop_t* uv_loop);
+
+ /**
+ * Start reading
+ * @return true on success
+ */
+ bool startRead(DataFunction dataFunction, EndFunction endFunction);
+
+ //! libuv pipe
+ uv_pipe_t* uv_pipe() const { return UVPipe_.get(); }
+ //! uv_pipe() casted to libuv stream
+ uv_stream_t* uv_stream() const { return static_cast<uv_stream_t*>(UVPipe_); }
+ //! uv_pipe() casted to libuv handle
+ uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(UVPipe_); }
+
+private:
+ // -- Libuv callbacks
+ static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ 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_;
+ EndFunction EndFunction_;
+};
+
+void cmUVPipeBuffer::reset()
+{
+ if (UVPipe_.get() != nullptr) {
+ EndFunction_ = nullptr;
+ DataFunction_ = nullptr;
+ Buffer_.clear();
+ Buffer_.shrink_to_fit();
+ UVPipe_.reset();
+ }
+}
+
+bool cmUVPipeBuffer::init(uv_loop_t* uv_loop)
+{
+ reset();
+ if (uv_loop == nullptr) {
+ return false;
+ }
+ int ret = UVPipe_.init(*uv_loop, 0, this);
+ return (ret == 0);
+}
+
+bool cmUVPipeBuffer::startRead(DataFunction dataFunction,
+ EndFunction endFunction)
+{
+ if (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,
+ &cmUVPipeBuffer::UVData);
+ return (ret == 0);
+}
+
+void cmUVPipeBuffer::UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(handle->data);
+ pipe.Buffer_.resize(suggestedSize);
+ buf->base = pipe.Buffer_.data();
+ buf->len = static_cast<unsigned long>(pipe.Buffer_.size());
+}
+
+void cmUVPipeBuffer::UVData(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(stream->data);
+ if (nread > 0) {
+ if (buf->base != nullptr) {
+ // Call data function
+ pipe.DataFunction_(DataRange(buf->base, buf->base + nread));
+ }
+ } else if (nread < 0) {
+ // Save the end function on the stack before resetting the pipe
+ EndFunction efunc;
+ efunc.swap(pipe.EndFunction_);
+ // Reset pipe before calling the end function
+ pipe.reset();
+ // Call end function
+ efunc((nread == UV_EOF) ? 0 : nread);
+ }
+}
+
+/**
+ * @brief External process management class
+ */
+class cmUVReadOnlyProcess
+{
+public:
+ // -- Types
+ //! @brief Process settings
+ struct SetupT
+ {
+ std::string WorkingDirectory;
+ std::vector<std::string> Command;
+ cmWorkerPool::ProcessResultT* Result = nullptr;
+ 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_; }
+
+ // -- Runtime
+ void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory = std::string());
+ bool start(uv_loop_t* uv_loop, std::function<void()> finishedCallback);
+
+private:
+ // -- Libuv callbacks
+ static void UVExit(uv_process_t* handle, int64_t exitStatus, int termSignal);
+ void UVPipeOutData(cmUVPipeBuffer::DataRange data);
+ void UVPipeOutEnd(ssize_t error);
+ void UVPipeErrData(cmUVPipeBuffer::DataRange data);
+ void UVPipeErrEnd(ssize_t error);
+ void UVTryFinish();
+
+private:
+ // -- Setup
+ SetupT Setup_;
+ // -- Runtime
+ bool IsStarted_ = false;
+ bool IsFinished_ = false;
+ std::function<void()> FinishedCallback_;
+ std::vector<const char*> CommandPtr_;
+ std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
+ uv_process_options_t UVOptions_;
+ cm::uv_process_ptr UVProcess_;
+ cmUVPipeBuffer UVPipeOut_;
+ cmUVPipeBuffer UVPipeErr_;
+};
+
+void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result,
+ bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ Setup_.WorkingDirectory = workingDirectory;
+ Setup_.Command = command;
+ Setup_.Result = result;
+ Setup_.MergedOutput = mergedOutput;
+}
+
+bool cmUVReadOnlyProcess::start(uv_loop_t* uv_loop,
+ std::function<void()> finishedCallback)
+{
+ if (IsStarted() || (Result() == nullptr)) {
+ return false;
+ }
+
+ // Reset result before the start
+ 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());
+ }
+ CommandPtr_.push_back(nullptr);
+ } else {
+ Result()->ErrorMessage = "Empty command";
+ }
+
+ if (!Result()->error()) {
+ if (!UVPipeOut_.init(uv_loop)) {
+ Result()->ErrorMessage = "libuv stdout pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ if (!UVPipeErr_.init(uv_loop)) {
+ Result()->ErrorMessage = "libuv stderr pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ // -- Setup process stdio options
+ // stdin
+ UVOptionsStdIO_[0].flags = UV_IGNORE;
+ UVOptionsStdIO_[0].data.stream = nullptr;
+ // stdout
+ UVOptionsStdIO_[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
+ // stderr
+ UVOptionsStdIO_[2].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[2].data.stream = 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();
+
+ // -- Spawn process
+ int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this);
+ if (uvErrorCode != 0) {
+ Result()->ErrorMessage = "libuv process spawn failed";
+ if (const char* uvErr = uv_strerror(uvErrorCode)) {
+ Result()->ErrorMessage += ": ";
+ Result()->ErrorMessage += uvErr;
+ }
+ }
+ }
+ // -- Start reading from stdio streams
+ if (!Result()->error()) {
+ if (!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";
+ }
+ }
+ if (!Result()->error()) {
+ if (!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";
+ }
+ }
+
+ if (!Result()->error()) {
+ IsStarted_ = true;
+ FinishedCallback_ = std::move(finishedCallback);
+ } else {
+ // Clear libuv handles and finish
+ UVProcess_.reset();
+ UVPipeOut_.reset();
+ UVPipeErr_.reset();
+ CommandPtr_.clear();
+ }
+
+ return IsStarted();
+}
+
+void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus,
+ int termSignal)
+{
+ auto& proc = *reinterpret_cast<cmUVReadOnlyProcess*>(handle->data);
+ if (proc.IsStarted() && !proc.IsFinished()) {
+ // Set error message on demand
+ proc.Result()->ExitStatus = exitStatus;
+ proc.Result()->TermSignal = termSignal;
+ if (!proc.Result()->error()) {
+ if (termSignal != 0) {
+ proc.Result()->ErrorMessage = "Process was terminated by signal ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->TermSignal);
+ } else if (exitStatus != 0) {
+ proc.Result()->ErrorMessage = "Process failed with return value ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->ExitStatus);
+ }
+ }
+
+ // Reset process handle
+ proc.UVProcess_.reset();
+ // Try finish
+ proc.UVTryFinish();
+ }
+}
+
+void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data)
+{
+ Result()->StdOut.append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeOutEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !Result()->error()) {
+ Result()->ErrorMessage =
+ "Reading from stdout pipe failed with libuv error code ";
+ Result()->ErrorMessage += std::to_string(error);
+ }
+ // Try finish
+ UVTryFinish();
+}
+
+void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data)
+{
+ std::string* str =
+ Setup_.MergedOutput ? &Result()->StdOut : &Result()->StdErr;
+ str->append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeErrEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !Result()->error()) {
+ Result()->ErrorMessage =
+ "Reading from stderr pipe failed with libuv error code ";
+ Result()->ErrorMessage += std::to_string(error);
+ }
+ // Try finish
+ UVTryFinish();
+}
+
+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)) {
+ return;
+ }
+ IsFinished_ = true;
+ FinishedCallback_();
+}
+
+/**
+ * @brief Worker pool worker thread
+ */
+class cmWorkerPoolWorker
+{
+public:
+ cmWorkerPoolWorker(uv_loop_t& uvLoop);
+ ~cmWorkerPoolWorker();
+
+ cmWorkerPoolWorker(cmWorkerPoolWorker const&) = delete;
+ cmWorkerPoolWorker& operator=(cmWorkerPoolWorker const&) = delete;
+
+ /**
+ * Set the internal thread
+ */
+ void SetThread(std::thread&& aThread) { Thread_ = std::move(aThread); }
+
+ /**
+ * Run an external process
+ */
+ bool RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+private:
+ // -- Libuv callbacks
+ static void UVProcessStart(uv_async_t* handle);
+ void UVProcessFinished();
+
+private:
+ // -- Process management
+ struct
+ {
+ std::mutex Mutex;
+ cm::uv_async_ptr Request;
+ std::condition_variable Condition;
+ std::unique_ptr<cmUVReadOnlyProcess> ROP;
+ } Proc_;
+ // -- System thread
+ std::thread Thread_;
+};
+
+cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop)
+{
+ Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
+}
+
+cmWorkerPoolWorker::~cmWorkerPoolWorker()
+{
+ if (Thread_.joinable()) {
+ Thread_.join();
+ }
+}
+
+bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ if (command.empty()) {
+ return false;
+ }
+ // Create process instance
+ {
+ std::lock_guard<std::mutex> lock(Proc_.Mutex);
+ Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
+ Proc_.ROP->setup(&result, true, command, workingDirectory);
+ }
+ // Send asynchronous process start request to libuv loop
+ 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);
+ }
+ }
+ return !result.error();
+}
+
+void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
+{
+ auto* wrk = reinterpret_cast<cmWorkerPoolWorker*>(handle->data);
+ bool startFailed = false;
+ {
+ auto& Proc = wrk->Proc_;
+ std::lock_guard<std::mutex> lock(Proc.Mutex);
+ if (Proc.ROP && !Proc.ROP->IsStarted()) {
+ startFailed =
+ !Proc.ROP->start(handle->loop, [wrk] { wrk->UVProcessFinished(); });
+ }
+ }
+ // Clean up if starting of the process failed
+ if (startFailed) {
+ wrk->UVProcessFinished();
+ }
+}
+
+void cmWorkerPoolWorker::UVProcessFinished()
+{
+ {
+ std::lock_guard<std::mutex> lock(Proc_.Mutex);
+ if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) {
+ Proc_.ROP.reset();
+ }
+ }
+ // Notify idling thread
+ Proc_.Condition.notify_one();
+}
+
+/**
+ * @brief Private worker pool internals
+ */
+class cmWorkerPoolInternal
+{
+public:
+ // -- Constructors
+ cmWorkerPoolInternal(cmWorkerPool* pool);
+ ~cmWorkerPoolInternal();
+
+ /**
+ * Runs the libuv loop.
+ */
+ bool Process();
+
+ /**
+ * Clear queue and abort threads.
+ */
+ void Abort();
+
+ /**
+ * Push a job to the queue and notify a worker.
+ */
+ bool PushJob(cmWorkerPool::JobHandleT&& jobHandle);
+
+ /**
+ * Worker thread main loop method.
+ */
+ void Work(unsigned int workerIndex);
+
+ // -- Request slots
+ 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;
+#endif
+ std::unique_ptr<uv_loop_t> UVLoop;
+ cm::uv_async_ptr UVRequestBegin;
+ cm::uv_async_ptr UVRequestEnd;
+
+ // -- Thread pool and job queue
+ std::mutex Mutex;
+ bool Processing = false;
+ bool Aborting = false;
+ bool FenceProcessing = false;
+ unsigned int WorkersRunning = 0;
+ unsigned int WorkersIdle = 0;
+ unsigned int JobsProcessing = 0;
+ std::deque<cmWorkerPool::JobHandleT> Queue;
+ std::condition_variable Condition;
+ std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers;
+
+ // -- References
+ cmWorkerPool* Pool = nullptr;
+};
+
+void cmWorkerPool::ProcessResultT::reset()
+{
+ ExitStatus = 0;
+ TermSignal = 0;
+ if (!StdOut.empty()) {
+ StdOut.clear();
+ StdOut.shrink_to_fit();
+ }
+ if (!StdErr.empty()) {
+ StdErr.clear();
+ StdErr.shrink_to_fit();
+ }
+ if (!ErrorMessage.empty()) {
+ ErrorMessage.clear();
+ ErrorMessage.shrink_to_fit();
+ }
+}
+
+cmWorkerPoolInternal::cmWorkerPoolInternal(cmWorkerPool* pool)
+ : Pool(pool)
+{
+ // Initialize libuv loop
+ uv_disable_stdio_inheritance();
+#ifdef CMAKE_UV_SIGNAL_HACK
+ UVHackRAII = cm::make_unique<cmUVSignalHackRAII>();
+#endif
+ UVLoop = cm::make_unique<uv_loop_t>();
+ uv_loop_init(UVLoop.get());
+}
+
+cmWorkerPoolInternal::~cmWorkerPoolInternal()
+{
+ uv_loop_close(UVLoop.get());
+}
+
+bool cmWorkerPoolInternal::Process()
+{
+ // Reset state flags
+ Processing = true;
+ Aborting = false;
+ // Initialize libuv asynchronous request
+ UVRequestBegin.init(*UVLoop, &cmWorkerPoolInternal::UVSlotBegin, this);
+ UVRequestEnd.init(*UVLoop, &cmWorkerPoolInternal::UVSlotEnd, this);
+ // Send begin request
+ UVRequestBegin.send();
+ // Run libuv loop
+ bool success = (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0);
+ // Update state flags
+ Processing = false;
+ Aborting = false;
+ return success;
+}
+
+void cmWorkerPoolInternal::Abort()
+{
+ bool notifyThreads = false;
+ // Clear all jobs and set abort flag
+ {
+ std::lock_guard<std::mutex> guard(Mutex);
+ if (Processing && !Aborting) {
+ // Register abort and clear queue
+ Aborting = true;
+ Queue.clear();
+ notifyThreads = true;
+ }
+ }
+ if (notifyThreads) {
+ // Wake threads
+ Condition.notify_all();
+ }
+}
+
+inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle)
+{
+ std::lock_guard<std::mutex> guard(Mutex);
+ if (Aborting) {
+ return false;
+ }
+ // Append the job to the queue
+ Queue.emplace_back(std::move(jobHandle));
+ // Notify an idle worker if there's one
+ if (WorkersIdle != 0) {
+ Condition.notify_one();
+ }
+ // Return success
+ return true;
+}
+
+void cmWorkerPoolInternal::UVSlotBegin(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Create worker threads
+ {
+ unsigned int const num = gint.Pool->ThreadCount();
+ // Create workers
+ gint.Workers.reserve(num);
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers.emplace_back(
+ cm::make_unique<cmWorkerPoolWorker>(*gint.UVLoop));
+ }
+ // Start worker threads
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers[ii]->SetThread(
+ std::thread(&cmWorkerPoolInternal::Work, &gint, ii));
+ }
+ }
+ // Destroy begin request
+ gint.UVRequestBegin.reset();
+}
+
+void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Join and destroy worker threads
+ gint.Workers.clear();
+ // Destroy end request
+ gint.UVRequestEnd.reset();
+}
+
+void cmWorkerPoolInternal::Work(unsigned int workerIndex)
+{
+ cmWorkerPool::JobHandleT jobHandle;
+ std::unique_lock<std::mutex> uLock(Mutex);
+ // Increment running workers count
+ ++WorkersRunning;
+ // Enter worker main loop
+ while (true) {
+ // Abort on request
+ if (Aborting) {
+ break;
+ }
+ // Wait for new jobs
+ if (Queue.empty()) {
+ ++WorkersIdle;
+ Condition.wait(uLock);
+ --WorkersIdle;
+ continue;
+ }
+
+ // Check for fence jobs
+ if (FenceProcessing || Queue.front()->IsFence()) {
+ if (JobsProcessing != 0) {
+ Condition.wait(uLock);
+ continue;
+ }
+ // No jobs get processed. Set the fence job processing flag.
+ FenceProcessing = true;
+ }
+
+ // Pop next job from queue
+ jobHandle = std::move(Queue.front());
+ Queue.pop_front();
+
+ // Unlocked scope for job processing
+ ++JobsProcessing;
+ {
+ uLock.unlock();
+ jobHandle->Work(Pool, workerIndex); // Process job
+ jobHandle.reset(); // Destroy job
+ uLock.lock();
+ }
+ --JobsProcessing;
+
+ // Was this a fence job?
+ if (FenceProcessing) {
+ FenceProcessing = false;
+ Condition.notify_all();
+ }
+ }
+
+ // Decrement running workers count
+ if (--WorkersRunning == 0) {
+ // Last worker thread about to finish. Send libuv event.
+ UVRequestEnd.send();
+ }
+}
+
+cmWorkerPool::JobT::~JobT() = default;
+
+bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ // Get worker by index
+ auto* wrk = Pool_->Int_->Workers.at(WorkerIndex_).get();
+ return wrk->RunProcess(result, command, workingDirectory);
+}
+
+cmWorkerPool::cmWorkerPool()
+ : Int_(cm::make_unique<cmWorkerPoolInternal>(this))
+{
+}
+
+cmWorkerPool::~cmWorkerPool() = default;
+
+void cmWorkerPool::SetThreadCount(unsigned int threadCount)
+{
+ if (!Int_->Processing) {
+ ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
+ }
+}
+
+bool cmWorkerPool::Process(void* userData)
+{
+ // Setup user data
+ UserData_ = userData;
+ // Run libuv loop
+ bool success = Int_->Process();
+ // Clear user data
+ UserData_ = nullptr;
+ // Return
+ return success;
+}
+
+bool cmWorkerPool::PushJob(JobHandleT&& jobHandle)
+{
+ return Int_->PushJob(std::move(jobHandle));
+}
+
+void cmWorkerPool::Abort()
+{
+ Int_->Abort();
+}
diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h
new file mode 100644
index 000000000..f08bb4f8d
--- /dev/null
+++ b/Source/cmWorkerPool.h
@@ -0,0 +1,226 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmWorkerPool_h
+#define cmWorkerPool_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmAlgorithms.h" // IWYU pragma: keep
+
+#include <memory> // IWYU pragma: keep
+#include <stdint.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+// -- Types
+class cmWorkerPoolInternal;
+
+/** @class cmWorkerPool
+ * @brief Thread pool with job queue
+ */
+class cmWorkerPool
+{
+public:
+ /**
+ * Return value and output of an external process.
+ */
+ struct ProcessResultT
+ {
+ void reset();
+ bool error() const
+ {
+ return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
+ }
+
+ std::int64_t ExitStatus = 0;
+ int TermSignal = 0;
+ std::string StdOut;
+ std::string StdErr;
+ std::string ErrorMessage;
+ };
+
+ /**
+ * Abstract job class for concurrent job processing.
+ */
+ class JobT
+ {
+ public:
+ JobT(JobT const&) = delete;
+ JobT& operator=(JobT const&) = delete;
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~JobT();
+
+ /**
+ * Fence job flag
+ *
+ * Fence jobs require that:
+ * - all jobs before in the queue have been processed
+ * - no jobs later in the queue will be processed before this job was
+ * processed
+ */
+ bool IsFence() const { return Fence_; }
+
+ protected:
+ /**
+ * Protected default constructor
+ */
+ JobT(bool fence = false)
+ : Fence_(fence)
+ {
+ }
+
+ /**
+ * Abstract processing interface that must be implement in derived classes.
+ */
+ virtual void Process() = 0;
+
+ /**
+ * Get the worker pool.
+ * Only valid during the JobT::Process() call!
+ */
+ cmWorkerPool* Pool() const { return Pool_; }
+
+ /**
+ * Get the user data.
+ * Only valid during the JobT::Process() call!
+ */
+ void* UserData() const { return Pool_->UserData(); };
+
+ /**
+ * Get the worker index.
+ * This is the index of the thread processing this job and is in the range
+ * [0..ThreadCount).
+ * Concurrently processing jobs will never have the same WorkerIndex().
+ * Only valid during the JobT::Process() call!
+ */
+ unsigned int WorkerIndex() const { return WorkerIndex_; }
+
+ /**
+ * Run an external read only process.
+ * Use only during JobT::Process() call!
+ */
+ bool RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+ private:
+ //! Needs access to Work()
+ friend class cmWorkerPoolInternal;
+ //! Worker thread entry method.
+ void Work(cmWorkerPool* pool, unsigned int workerIndex)
+ {
+ Pool_ = pool;
+ WorkerIndex_ = workerIndex;
+ this->Process();
+ }
+
+ private:
+ cmWorkerPool* Pool_ = nullptr;
+ unsigned int WorkerIndex_ = 0;
+ bool Fence_ = false;
+ };
+
+ /**
+ * Job handle type
+ */
+ typedef std::unique_ptr<JobT> JobHandleT;
+
+ /**
+ * Fence job base class
+ */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ //! Does nothing
+ void Process() override{};
+ };
+
+ /**
+ * Fence job that aborts the worker pool.
+ *
+ * Useful as the last job in the job queue.
+ */
+ class JobEndT : JobFenceT
+ {
+ public:
+ //! Does nothing
+ void Process() override { Pool()->Abort(); }
+ };
+
+public:
+ // -- Methods
+ cmWorkerPool();
+ ~cmWorkerPool();
+
+ /**
+ * Number of worker threads.
+ */
+ unsigned int ThreadCount() const { return ThreadCount_; }
+
+ /**
+ * Set the number of worker threads.
+ *
+ * Calling this method during Process() has no effect.
+ */
+ void SetThreadCount(unsigned int threadCount);
+
+ /**
+ * Blocking function that starts threads to process all Jobs in the queue.
+ *
+ * This method blocks until a job calls the Abort() method.
+ * @arg threadCount Number of threads to process jobs.
+ * @arg userData Common user data pointer available in all Jobs.
+ */
+ bool Process(void* userData = nullptr);
+
+ /**
+ * User data reference passed to Process().
+ *
+ * Only valid during Process().
+ */
+ void* UserData() const { return UserData_; }
+
+ // -- Job processing interface
+
+ /**
+ * Clears the job queue and aborts all worker threads.
+ *
+ * This method is thread safe and can be called from inside a job.
+ */
+ void Abort();
+
+ /**
+ * Push job to the queue.
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ bool PushJob(JobHandleT&& jobHandle);
+
+ /**
+ * Push job to the queue
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ template <class T, typename... Args>
+ bool EmplaceJob(Args&&... args)
+ {
+ return PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
+ }
+
+private:
+ void* UserData_ = nullptr;
+ unsigned int ThreadCount_ = 1;
+ std::unique_ptr<cmWorkerPoolInternal> Int_;
+};
+
+#endif
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
index 1f18ce7a3..d4a164de6 100644
--- a/Source/cmWorkingDirectory.h
+++ b/Source/cmWorkingDirectory.h
@@ -22,6 +22,9 @@ public:
cmWorkingDirectory(std::string const& newdir);
~cmWorkingDirectory();
+ cmWorkingDirectory(const cmWorkingDirectory&) = delete;
+ cmWorkingDirectory& operator=(const cmWorkingDirectory&) = delete;
+
bool SetDirectory(std::string const& newdir);
void Pop();
bool Failed() const { return ResultCode != 0; }
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index 1b161987a..c33bb7e8f 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -177,6 +177,11 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
WriteLaunchActionAttribute(xout, "stopOnEveryMainThreadCheckerIssue",
"XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
+ if (this->Target->GetTarget()->GetPropertyAsBool(
+ "XCODE_SCHEME_DEBUG_AS_ROOT")) {
+ xout.Attribute("debugAsWhichUser", "root");
+ }
+
// Diagnostics tab end
if (IsExecutable(this->Target)) {
diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx
index 9d2a3c454..f1ce60814 100644
--- a/Source/cmXMLWriter.cxx
+++ b/Source/cmXMLWriter.cxx
@@ -23,7 +23,7 @@ cmXMLWriter::~cmXMLWriter()
void cmXMLWriter::StartDocument(const char* encoding)
{
- this->Output << "<?xml version=\"1.0\" encoding=\"" << encoding << "\"?>";
+ this->Output << R"(<?xml version="1.0" encoding=")" << encoding << "\"?>";
}
void cmXMLWriter::EndDocument()
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
index 1df8a09d7..512e1031d 100644
--- a/Source/cmXMLWriter.h
+++ b/Source/cmXMLWriter.h
@@ -146,6 +146,8 @@ public:
xmlwr.StartDocument();
}
~cmXMLDocument() { xmlwr.EndDocument(); }
+ cmXMLDocument(const cmXMLDocument&) = delete;
+ cmXMLDocument& operator=(const cmXMLDocument&) = delete;
private:
friend class cmXMLElement;
@@ -172,6 +174,9 @@ public:
}
~cmXMLElement() { xmlwr.EndElement(); }
+ cmXMLElement(const cmXMLElement&) = delete;
+ cmXMLElement& operator=(const cmXMLElement&) = delete;
+
template <typename T>
cmXMLElement& Attribute(const char* name, T const& value)
{
diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c
index 52af4a6f4..62e7e8c8c 100644
--- a/Source/cm_utf8.c
+++ b/Source/cm_utf8.c
@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cm_utf8.h"
+#include <string.h>
+
/*
RFC 3629
07-bit: 0xxxxxxx
@@ -71,7 +73,34 @@ const char* cm_utf8_decode_character(const char* first, const char* last,
return 0;
}
+ /* UTF-16 surrogate halves. */
+ if (0xD800 <= uc && uc <= 0xDFFF) {
+ return 0;
+ }
+
+ /* Invalid codepoints. */
+ if (0x10FFFF < uc) {
+ return 0;
+ }
+
*pc = uc;
return first;
}
}
+
+int cm_utf8_is_valid(const char* s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ const char* last = s + strlen(s);
+ const char* pos = s;
+ unsigned int pc;
+
+ while (pos != last && (pos = cm_utf8_decode_character(pos, last, &pc))) {
+ /* Nothing to do. */
+ }
+
+ return pos == last;
+}
diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h
index fcb43e0e4..27dc5591f 100644
--- a/Source/cm_utf8.h
+++ b/Source/cm_utf8.h
@@ -13,6 +13,10 @@ extern "C" {
const char* cm_utf8_decode_character(const char* first, const char* last,
unsigned int* pc);
+/** Returns whether a C string is a sequence of valid UTF-8 encoded Unicode
+ codepoints. Returns non-zero on success. */
+int cm_utf8_is_valid(const char* s);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 8023298f9..3772f0998 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -9,7 +9,7 @@
#include "cmDocumentationFormatter.h"
#include "cmDuration.h"
#include "cmExternalMakefileProjectGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -48,7 +48,6 @@
#if defined(_WIN32) && !defined(__CYGWIN__)
# if !defined(CMAKE_BOOT_MINGW)
# include "cmGlobalBorlandMakefileGenerator.h"
-# include "cmGlobalGhsMultiGenerator.h"
# include "cmGlobalJOMMakefileGenerator.h"
# include "cmGlobalNMakeMakefileGenerator.h"
# include "cmGlobalVisualStudio10Generator.h"
@@ -84,6 +83,10 @@
# include "cmExtraEclipseCDT4Generator.h"
#endif
+#if defined(__linux__) || defined(_WIN32)
+# include "cmGlobalGhsMultiGenerator.h"
+#endif
+
#if defined(__APPLE__)
# if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmGlobalXCodeGenerator.h"
@@ -99,6 +102,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <cstring>
+#include <initializer_list>
#include <iostream>
#include <iterator>
#include <memory> // IWYU pragma: keep
@@ -115,10 +119,8 @@ typedef std::unordered_map<std::string, Json::Value> JsonValueMapType;
} // namespace
-static bool cmakeCheckStampFile(const std::string& stampName,
- bool verbose = true);
-static bool cmakeCheckStampList(const std::string& stampList,
- bool verbose = true);
+static bool cmakeCheckStampFile(const std::string& stampName);
+static bool cmakeCheckStampList(const std::string& stampList);
void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
void* ctx, const char* /*unused*/,
@@ -139,7 +141,7 @@ cmake::cmake(Role role, cmState::Mode mode)
this->DebugOutput = false;
this->DebugTryCompile = false;
this->ClearBuildSystem = false;
- this->FileComparison = new cmFileTimeComparison;
+ this->FileTimeCache = new cmFileTimeCache;
this->State = new cmState;
this->State->SetMode(mode);
@@ -157,6 +159,9 @@ cmake::cmake(Role role, cmState::Mode mode)
#endif
this->GlobalGenerator = nullptr;
+ this->GeneratorInstanceSet = false;
+ this->GeneratorPlatformSet = false;
+ this->GeneratorToolsetSet = false;
this->CurrentWorkingMode = NORMAL_MODE;
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -172,6 +177,10 @@ cmake::cmake(Role role, cmState::Mode mode)
this->AddProjectCommands();
}
+ if (mode == cmState::Project) {
+ this->LoadEnvironmentPresets();
+ }
+
// Make sure we can capture the build tool output.
cmSystemTools::EnableVSConsoleOutput();
@@ -223,7 +232,7 @@ cmake::~cmake()
#ifdef CMAKE_BUILD_WITH_CMAKE
delete this->VariableWatch;
#endif
- delete this->FileComparison;
+ delete this->FileTimeCache;
}
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -239,7 +248,7 @@ Json::Value cmake::ReportVersionJson() const
return version;
}
-Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
+Json::Value cmake::ReportCapabilitiesJson() const
{
Json::Value obj = Json::objectValue;
@@ -275,18 +284,19 @@ Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
generators.append(i.second);
}
obj["generators"] = generators;
- obj["serverMode"] = haveServerMode;
+ obj["fileApi"] = cmFileAPI::ReportCapabilities();
+ obj["serverMode"] = true;
return obj;
}
#endif
-std::string cmake::ReportCapabilities(bool haveServerMode) const
+std::string cmake::ReportCapabilities() const
{
std::string result;
#if defined(CMAKE_BUILD_WITH_CMAKE)
Json::FastWriter writer;
- result = writer.write(this->ReportCapabilitiesJson(haveServerMode));
+ result = writer.write(this->ReportCapabilitiesJson());
#else
result = "Not supported";
#endif
@@ -610,6 +620,35 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
return packageFound;
}
+void cmake::LoadEnvironmentPresets()
+{
+ std::string envGenVar;
+ bool hasEnvironmentGenerator = false;
+ if (cmSystemTools::GetEnv("CMAKE_GENERATOR", envGenVar)) {
+ hasEnvironmentGenerator = true;
+ this->EnvironmentGenerator = envGenVar;
+ }
+
+ auto readGeneratorVar = [&](std::string name, std::string& key) {
+ std::string varValue;
+ if (cmSystemTools::GetEnv(name, varValue)) {
+ if (hasEnvironmentGenerator) {
+ key = varValue;
+ } else if (!this->GetIsInTryCompile()) {
+ std::string message = "Warning: Environment variable ";
+ message += name;
+ message += " will be ignored, because CMAKE_GENERATOR ";
+ message += "is not set.";
+ cmSystemTools::Message(message, "Warning");
+ }
+ }
+ };
+
+ readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
+ readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
+ readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
+}
+
// Parse the args
void cmake::SetArgs(const std::vector<std::string>& args)
{
@@ -708,6 +747,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
this->GraphVizFile = path;
if (this->GraphVizFile.empty()) {
cmSystemTools::Error("No file specified for --graphviz");
+ return;
}
} else if (arg.find("--debug-trycompile", 0) == 0) {
std::cout << "debug trycompile on\n";
@@ -715,6 +755,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
} else if (arg.find("--debug-output", 0) == 0) {
std::cout << "Running with debug output on.\n";
this->SetDebugOutputOn(true);
+ } else if (arg.find("--loglevel=", 0) == 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);
} else if (arg.find("--trace-expand", 0) == 0) {
std::cout << "Running with expanded trace output on.\n";
this->SetTrace(true);
@@ -756,7 +804,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmSystemTools::Error("Multiple -A options not allowed");
return;
}
- this->GeneratorPlatform = value;
+ this->SetGeneratorPlatform(value);
havePlatform = true;
} else if (arg.find("-T", 0) == 0) {
std::string value = arg.substr(2);
@@ -772,7 +820,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmSystemTools::Error("Multiple -T options not allowed");
return;
}
- this->GeneratorToolset = value;
+ this->SetGeneratorToolset(value);
haveToolset = true;
} else if (arg.find("-G", 0) == 0) {
std::string value = arg.substr(2);
@@ -787,21 +835,31 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
if (!gen) {
- const char* kdevError = nullptr;
+ std::string kdevError;
if (value.find("KDevelop3", 0) != std::string::npos) {
kdevError = "\nThe KDevelop3 generator is not supported anymore.";
}
- cmSystemTools::Error("Could not create named generator ",
- value.c_str(), kdevError);
+ cmSystemTools::Error("Could not create named generator " + value +
+ kdevError);
this->PrintGeneratorList();
- } else {
- this->SetGlobalGenerator(gen);
+ return;
}
+ this->SetGlobalGenerator(gen);
}
// no option assume it is the path to the source or an existing build
else {
- this->SetDirectoriesFromFile(arg.c_str());
+ 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 = "";
+ }
}
}
@@ -825,7 +883,26 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
}
-void cmake::SetDirectoriesFromFile(const char* arg)
+cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
+{
+ using LevelsPair = std::pair<std::string, LogLevel>;
+ static const std::vector<LevelsPair> levels = {
+ { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING },
+ { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS },
+ { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
+ { "trace", LogLevel::LOG_TRACE }
+ };
+
+ const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+
+ const auto it = std::find_if(levels.cbegin(), levels.cend(),
+ [&levelStrLowCase](const LevelsPair& p) {
+ return p.first == levelStrLowCase;
+ });
+ return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+}
+
+void cmake::SetDirectoriesFromFile(const std::string& arg)
{
// Check if the argument refers to a CMakeCache.txt or
// CMakeLists.txt file.
@@ -937,8 +1014,8 @@ int cmake::AddCMakePaths()
cmSystemTools::Error(
"Could not find CMAKE_ROOT !!!\n"
"CMake has most likely not been installed correctly.\n"
- "Modules directory not found in\n",
- cmSystemTools::GetCMakeRoot().c_str());
+ "Modules directory not found in\n" +
+ cmSystemTools::GetCMakeRoot());
return 0;
}
this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
@@ -969,10 +1046,7 @@ void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
std::vector<std::string> names = gen->GetGeneratorNames();
if (includeNamesWithPlatform) {
- std::vector<std::string> namesWithPlatform =
- gen->GetGeneratorNamesWithPlatform();
- names.insert(names.end(), namesWithPlatform.begin(),
- namesWithPlatform.end());
+ cmAppend(names, gen->GetGeneratorNamesWithPlatform());
}
for (std::string const& name : names) {
@@ -1105,7 +1179,7 @@ std::string cmake::FindCacheFile(const std::string& binaryDir)
if (cmSystemTools::FileExists(cmakeFiles)) {
std::string cachePathFound =
cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
- cachePath.c_str(), "/");
+ cachePath, "/");
if (!cachePathFound.empty()) {
cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
}
@@ -1416,8 +1490,7 @@ int cmake::ActualConfigure()
if (const std::string* instance =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
- if (!this->GeneratorInstance.empty() &&
- this->GeneratorInstance != *instance) {
+ if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
std::string message = "Error: generator instance: ";
message += this->GeneratorInstance;
message += "\nDoes not match the instance used previously: ";
@@ -1435,7 +1508,7 @@ int cmake::ActualConfigure()
if (const std::string* platformName =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
- if (!this->GeneratorPlatform.empty() &&
+ if (this->GeneratorPlatformSet &&
this->GeneratorPlatform != *platformName) {
std::string message = "Error: generator platform: ";
message += this->GeneratorPlatform;
@@ -1454,7 +1527,7 @@ int cmake::ActualConfigure()
if (const std::string* tsName =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
- if (!this->GeneratorToolset.empty() && this->GeneratorToolset != *tsName) {
+ if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
std::string message = "Error: generator toolset: ";
message += this->GeneratorToolset;
message += "\nDoes not match the toolset used previously: ";
@@ -1532,6 +1605,16 @@ int cmake::ActualConfigure()
std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
{
+ if (!this->EnvironmentGenerator.empty()) {
+ cmGlobalGenerator* gen =
+ this->CreateGlobalGenerator(this->EnvironmentGenerator);
+ if (!gen) {
+ cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
+ "generator doesn't exist. Using CMake default.");
+ } else {
+ return std::unique_ptr<cmGlobalGenerator>(gen);
+ }
+ }
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
std::string found;
// Try to find the newest VS installed on the computer and
@@ -1703,9 +1786,14 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
return ret;
}
ret = this->Generate();
+ if (ret) {
+ cmSystemTools::Message("CMake Generate step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
- this->UpdateProgress(message.c_str(), -1);
+ this->UpdateProgress(message, -1);
return ret;
}
@@ -1720,7 +1808,7 @@ int cmake::Generate()
this->GlobalGenerator->Generate();
if (!this->GraphVizFile.empty()) {
std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
- this->GenerateGraphViz(this->GraphVizFile.c_str());
+ this->GenerateGraphViz(this->GraphVizFile);
}
if (this->WarnUnusedCli) {
this->RunCheckForUnusedVariables();
@@ -1834,13 +1922,15 @@ void cmake::AddDefaultGenerators()
this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory());
- this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
# endif
this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
#endif
this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
#if defined(CMAKE_BUILD_WITH_CMAKE)
+# if defined(__linux__) || defined(_WIN32)
+ this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
+# endif
this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
#endif
#if defined(CMAKE_USE_WMAKE)
@@ -1892,11 +1982,10 @@ bool cmake::LoadCache(const std::string& path, bool internal,
std::set<std::string>& includes)
{
bool result = this->State->LoadCache(path, internal, excludes, includes);
- static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
- "CMAKE_CACHE_MINOR_VERSION" };
- for (const char* const* nameIt = cm::cbegin(entries);
- nameIt != cm::cend(entries); ++nameIt) {
- this->UnwatchUnusedCli(*nameIt);
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
}
return result;
}
@@ -1904,13 +1993,12 @@ bool cmake::LoadCache(const std::string& path, bool internal,
bool cmake::SaveCache(const std::string& path)
{
bool result = this->State->SaveCache(path, this->GetMessenger());
- static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
- "CMAKE_CACHE_MINOR_VERSION",
- "CMAKE_CACHE_PATCH_VERSION",
- "CMAKE_CACHEFILE_DIR" };
- for (const char* const* nameIt = cm::cbegin(entries);
- nameIt != cm::cend(entries); ++nameIt) {
- this->UnwatchUnusedCli(*nameIt);
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION",
+ "CMAKE_CACHE_PATCH_VERSION",
+ "CMAKE_CACHEFILE_DIR" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
}
return result;
}
@@ -1925,7 +2013,7 @@ void cmake::SetProgressCallback(ProgressCallbackType f)
this->ProgressCallback = std::move(f);
}
-void cmake::UpdateProgress(const char* msg, float prog)
+void cmake::UpdateProgress(const std::string& msg, float prog)
{
if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
this->ProgressCallback(msg, prog);
@@ -2017,8 +2105,8 @@ void cmake::UpdateConversionPathTable()
if (tablepath) {
cmsys::ifstream table(tablepath->c_str());
if (!table) {
- cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ",
- tablepath->c_str(), ". CMake can not open file.");
+ cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to " + *tablepath +
+ ". CMake can not open file.");
cmSystemTools::ReportLastSystemError("CMake can not open file.");
} else {
std::string a, b;
@@ -2142,7 +2230,7 @@ int cmake::CheckBuildSystem()
std::string dep_newest = *dep++;
for (; dep != depends.end(); ++dep) {
int result = 0;
- if (this->FileComparison->FileTimeCompare(dep_newest, *dep, &result)) {
+ if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) {
if (result < 0) {
dep_newest = *dep;
}
@@ -2161,7 +2249,7 @@ int cmake::CheckBuildSystem()
std::string out_oldest = *out++;
for (; out != outputs.end(); ++out) {
int result = 0;
- if (this->FileComparison->FileTimeCompare(out_oldest, *out, &result)) {
+ if (this->FileTimeCache->Compare(out_oldest, *out, &result)) {
if (result > 0) {
out_oldest = *out;
}
@@ -2178,8 +2266,7 @@ int cmake::CheckBuildSystem()
// If any output is older than any dependency then rerun.
{
int result = 0;
- if (!this->FileComparison->FileTimeCompare(out_oldest, dep_newest,
- &result) ||
+ if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) ||
result < 0) {
if (verbose) {
std::ostringstream msg;
@@ -2229,7 +2316,7 @@ void cmake::MarkCliAsUsed(const std::string& variable)
this->UsedCliVariables[variable] = true;
}
-void cmake::GenerateGraphViz(const char* fileName) const
+void cmake::GenerateGraphViz(const std::string& fileName) const
{
#ifdef CMAKE_BUILD_WITH_CMAKE
cmGraphVizWriter gvWriter(this->GetGlobalGenerator());
@@ -2239,8 +2326,7 @@ void cmake::GenerateGraphViz(const char* fileName) const
std::string fallbackSettingsFile = this->GetHomeDirectory();
fallbackSettingsFile += "/CMakeGraphVizOptions.cmake";
- gvWriter.ReadSettings(settingsFile.c_str(), fallbackSettingsFile.c_str());
-
+ gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
gvWriter.WritePerTargetFiles(fileName);
gvWriter.WriteTargetDependersFiles(fileName);
gvWriter.WriteGlobalFile(fileName);
@@ -2326,8 +2412,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
}
cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
if (!gen) {
- cmSystemTools::Error("Could not create named generator ",
- value.c_str());
+ cmSystemTools::Error("Could not create named generator " + value);
this->PrintGeneratorList();
} else {
this->SetGlobalGenerator(gen);
@@ -2354,7 +2439,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
outFile += "/CMakeLists.txt";
// Copy file
- if (!cmSystemTools::cmCopyFile(inFile, outFile)) {
+ if (!cmsys::SystemTools::CopyFileAlways(inFile, outFile)) {
std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
<< "\".\n";
return 1;
@@ -2412,7 +2497,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
return 0;
}
-static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
+static bool cmakeCheckStampFile(const std::string& stampName)
{
// The stamp file does not exist. Use the stamp dependencies to
// determine whether it is really out of date. This works in
@@ -2435,20 +2520,22 @@ static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
}
// Compare the stamp dependencies against the dependency file itself.
- cmFileTimeComparison ftc;
- std::string dep;
- while (cmSystemTools::GetLineFromStream(fin, dep)) {
- int result;
- if (!dep.empty() && dep[0] != '#' &&
- (!ftc.FileTimeCompare(stampDepends, dep, &result) || result < 0)) {
- // The stamp depends file is older than this dependency. The
- // build system is really out of date.
- std::cout << "CMake is re-running because " << stampName
- << " is out-of-date.\n";
- std::cout << " the file '" << dep << "'\n";
- std::cout << " is newer than '" << stampDepends << "'\n";
- std::cout << " result='" << result << "'\n";
- return false;
+ {
+ cmFileTimeCache ftc;
+ std::string dep;
+ while (cmSystemTools::GetLineFromStream(fin, dep)) {
+ int result;
+ if (!dep.empty() && dep[0] != '#' &&
+ (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
+ // The stamp depends file is older than this dependency. The
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " is out-of-date.\n";
+ std::cout << " the file '" << dep << "'\n";
+ std::cout << " is newer than '" << stampDepends << "'\n";
+ std::cout << " result='" << result << "'\n";
+ return false;
+ }
}
}
@@ -2464,21 +2551,15 @@ static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
stamp << "# CMake generation timestamp file for this directory.\n";
}
if (cmSystemTools::RenameFile(stampTemp, stampName)) {
- if (verbose) {
- // Notify the user why CMake is not re-running. It is safe to
- // just print to stdout here because this code is only reachable
- // through an undocumented flag used by the VS generator.
- std::cout << "CMake does not need to re-run because " << stampName
- << " is up-to-date.\n";
- }
+ // CMake does not need to re-run because the stamp file is up-to-date.
return true;
}
cmSystemTools::RemoveFile(stampTemp);
- cmSystemTools::Error("Cannot restore timestamp ", stampName.c_str());
+ cmSystemTools::Error("Cannot restore timestamp " + stampName);
return false;
}
-static bool cmakeCheckStampList(const std::string& stampList, bool verbose)
+static bool cmakeCheckStampList(const std::string& stampList)
{
// If the stamp list does not exist CMake must rerun to generate it.
if (!cmSystemTools::FileExists(stampList)) {
@@ -2496,7 +2577,7 @@ static bool cmakeCheckStampList(const std::string& stampList, bool verbose)
// Check each stamp.
std::string stampName;
while (cmSystemTools::GetLineFromStream(fin, stampName)) {
- if (!cmakeCheckStampFile(stampName, verbose)) {
+ if (!cmakeCheckStampFile(stampName)) {
return false;
}
}
@@ -2531,7 +2612,8 @@ cmMessenger* cmake::GetMessenger() const
return this->Messenger;
}
-int cmake::Build(int jobs, const std::string& dir, const std::string& target,
+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)
@@ -2617,12 +2699,12 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
}
}
- if (!cmakeCheckStampList(stampList, false)) {
+ if (!cmakeCheckStampList(stampList)) {
// Correctly initialize the home (=source) and home output (=binary)
// directories, which is required for running the generation step.
std::string homeOrig = this->GetHomeDirectory();
std::string homeOutputOrig = this->GetHomeOutputDirectory();
- this->SetDirectoriesFromFile(cachePath.c_str());
+ this->SetDirectoriesFromFile(cachePath);
this->AddProjectCommands();
@@ -2640,7 +2722,7 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
}
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
- this->UpdateProgress(message.c_str(), -1);
+ this->UpdateProgress(message, -1);
// Restore the previously set directories to their original value.
this->SetHomeDirectory(homeOrig);
@@ -2650,9 +2732,8 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
#endif
gen->PrintBuildCommandAdvice(std::cerr, jobs);
-
- return gen->Build(jobs, "", dir, projName, target, output, "", config, clean,
- false, verbose, cmDuration::zero(),
+ return gen->Build(jobs, "", dir, projName, targets, output, "", config,
+ clean, false, verbose, cmDuration::zero(),
cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
}
diff --git a/Source/cmake.h b/Source/cmake.h
index 53d44f148..fa4409aeb 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -26,7 +26,7 @@
class cmExternalMakefileProjectGeneratorFactory;
class cmFileAPI;
-class cmFileTimeComparison;
+class cmFileTimeCache;
class cmGlobalGenerator;
class cmGlobalGeneratorFactory;
class cmMakefile;
@@ -96,6 +96,19 @@ public:
FIND_PACKAGE_MODE
};
+ /** \brief Define log level constants. */
+ enum LogLevel
+ {
+ LOG_UNDEFINED,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_STATUS,
+ LOG_VERBOSE,
+ LOG_DEBUG,
+ LOG_TRACE
+ };
+
struct GeneratorInfo
{
std::string name;
@@ -123,9 +136,9 @@ public:
#if defined(CMAKE_BUILD_WITH_CMAKE)
Json::Value ReportVersionJson() const;
- Json::Value ReportCapabilitiesJson(bool haveServerMode) const;
+ Json::Value ReportCapabilitiesJson() const;
#endif
- std::string ReportCapabilities(bool haveServerMode) const;
+ std::string ReportCapabilities() const;
//@{
/**
@@ -162,7 +175,7 @@ public:
int Configure();
int ActualConfigure();
- ///! Break up a line like VAR:type="value" into var, type and value
+ //! Break up a line like VAR:type="value" into var, type and value
static bool ParseCacheEntry(const std::string& entry, std::string& var,
std::string& value,
cmStateEnums::CacheEntryType& type);
@@ -176,43 +189,46 @@ public:
bool DeleteCache(const std::string& path);
void PreLoadCMakeFiles();
- ///! Create a GlobalGenerator
+ //! Create a GlobalGenerator
cmGlobalGenerator* CreateGlobalGenerator(const std::string& name);
- ///! Return the global generator assigned to this instance of cmake
+ //! Return the global generator assigned to this instance of cmake
cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
- ///! Return the global generator assigned to this instance of cmake, const
+ //! Return the global generator assigned to this instance of cmake, const
const cmGlobalGenerator* GetGlobalGenerator() const
{
return this->GlobalGenerator;
}
- ///! Return the full path to where the CMakeCache.txt file should be.
+ //! Return the full path to where the CMakeCache.txt file should be.
static std::string FindCacheFile(const std::string& binaryDir);
- ///! Return the global generator assigned to this instance of cmake
+ //! Return the global generator assigned to this instance of cmake
void SetGlobalGenerator(cmGlobalGenerator*);
- ///! Get the names of the current registered generators
+ //! Get the names of the current registered generators
void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
bool includeNamesWithPlatform = true) const;
- ///! Set the name of the selected generator-specific instance.
+ //! Set the name of the selected generator-specific instance.
void SetGeneratorInstance(std::string const& instance)
{
this->GeneratorInstance = instance;
+ this->GeneratorInstanceSet = true;
}
- ///! Set the name of the selected generator-specific platform.
+ //! Set the name of the selected generator-specific platform.
void SetGeneratorPlatform(std::string const& ts)
{
this->GeneratorPlatform = ts;
+ this->GeneratorPlatformSet = true;
}
- ///! Set the name of the selected generator-specific toolset.
+ //! Set the name of the selected generator-specific toolset.
void SetGeneratorToolset(std::string const& ts)
{
this->GeneratorToolset = ts;
+ this->GeneratorToolsetSet = true;
}
const std::vector<std::string>& GetSourceExtensions() const
@@ -244,7 +260,7 @@ public:
* Given a variable name, return its value (as a string).
*/
const char* GetCacheDefinition(const std::string&) const;
- ///! Add an entry into the cache
+ //! Add an entry into the cache
void AddCacheEntry(const std::string& key, const char* value,
const char* helpString, int type);
@@ -263,17 +279,20 @@ public:
*/
int GetSystemInformation(std::vector<std::string>&);
- ///! Parse command line arguments
+ //! Parse environment variables
+ void LoadEnvironmentPresets();
+
+ //! Parse command line arguments
void SetArgs(const std::vector<std::string>& args);
- ///! Is this cmake running as a result of a TRY_COMPILE command
+ //! Is this cmake running as a result of a TRY_COMPILE command
bool GetIsInTryCompile() const;
void SetIsInTryCompile(bool b);
- ///! Parse command line arguments that might set cache values
+ //! Parse command line arguments that might set cache values
bool SetCacheArgs(const std::vector<std::string>&);
- using ProgressCallbackType = std::function<void(const char*, float)>;
+ using ProgressCallbackType = std::function<void(const std::string&, float)>;
/**
* Set the function used by GUIs to receive progress updates
* Function gets passed: message as a const char*, a progress
@@ -283,24 +302,24 @@ public:
*/
void SetProgressCallback(ProgressCallbackType f);
- ///! this is called by generators to update the progress
- void UpdateProgress(const char* msg, float prog);
+ //! this is called by generators to update the progress
+ void UpdateProgress(const std::string& msg, float prog);
#if defined(CMAKE_BUILD_WITH_CMAKE)
- ///! Get the variable watch object
+ //! Get the variable watch object
cmVariableWatch* GetVariableWatch() { return this->VariableWatch; }
#endif
std::vector<cmDocumentationEntry> GetGeneratorsDocumentation();
- ///! Set/Get a property of this target file
+ //! Set/Get a property of this target file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
const char* GetProperty(const std::string& prop);
bool GetPropertyAsBool(const std::string& prop);
- ///! Get or create an cmInstalledFile instance and return a pointer to it
+ //! Get or create an cmInstalledFile instance and return a pointer to it
cmInstalledFile* GetOrCreateInstalledFile(cmMakefile* mf,
const std::string& name);
@@ -311,13 +330,13 @@ public:
return this->InstalledFiles;
}
- ///! Do all the checks before running configure
+ //! Do all the checks before running configure
int DoPreConfigureChecks();
void SetWorkingMode(WorkingMode mode) { this->CurrentWorkingMode = mode; }
WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
- ///! Debug the try compile stuff by not deleting the files
+ //! Debug the try compile stuff by not deleting the files
bool GetDebugTryCompile() { return this->DebugTryCompile; }
void DebugTryCompileOn() { this->DebugTryCompile = true; }
@@ -329,7 +348,12 @@ public:
/**
* Get the file comparison class
*/
- cmFileTimeComparison* GetFileComparison() { return this->FileComparison; }
+ cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; }
+
+ // Get the selected log level for `message()` commands during the cmake run.
+ LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+ void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
+ static LogLevel StringToLogLevel(const std::string& levelStr);
// Do we want debug output during the cmake run.
bool GetDebugOutput() { return this->DebugOutput; }
@@ -423,13 +447,13 @@ public:
MessageType t, std::string const& text,
cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
- ///! run the --build option
- int Build(int jobs, const std::string& dir, const std::string& target,
- const std::string& config,
+ //! 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);
- ///! run the --open option
+ //! run the --open option
bool Open(const std::string& dir, bool dryRun);
void UnwatchUnusedCli(const std::string& var);
@@ -461,13 +485,16 @@ protected:
std::string GeneratorInstance;
std::string GeneratorPlatform;
std::string GeneratorToolset;
+ bool GeneratorInstanceSet;
+ bool GeneratorPlatformSet;
+ bool GeneratorToolsetSet;
- ///! read in a cmake list file to initialize the cache
+ //! read in a cmake list file to initialize the cache
void ReadListFile(const std::vector<std::string>& args,
const std::string& path);
bool FindPackage(const std::vector<std::string>& args);
- ///! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
+ //! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
/// If it is set, truncate it to 50kb
void TruncateOutputLog(const char* fname);
@@ -477,13 +504,13 @@ protected:
*/
int CheckBuildSystem();
- void SetDirectoriesFromFile(const char* arg);
+ void SetDirectoriesFromFile(const std::string& arg);
//! Make sure all commands are what they say they are and there is no
/// macros.
void CleanupCommandsAndMacros();
- void GenerateGraphViz(const char* fileName) const;
+ void GenerateGraphViz(const std::string& fileName) const;
private:
ProgressCallbackType ProgressCallback;
@@ -503,13 +530,14 @@ private:
std::string CheckStampFile;
std::string CheckStampList;
std::string VSSolutionFile;
+ std::string EnvironmentGenerator;
std::vector<std::string> SourceFileExtensions;
std::unordered_set<std::string> SourceFileExtensionsSet;
std::vector<std::string> HeaderFileExtensions;
std::unordered_set<std::string> HeaderFileExtensionsSet;
bool ClearBuildSystem;
bool DebugTryCompile;
- cmFileTimeComparison* FileComparison;
+ cmFileTimeCache* FileTimeCache;
std::string GraphVizFile;
InstalledFilesMap InstalledFiles;
@@ -524,6 +552,8 @@ private:
std::vector<std::string> TraceOnlyThisSources;
+ LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+
void UpdateConversionPathTable();
// Print a list of valid generators to stderr.
@@ -562,40 +592,38 @@ private:
"not errors." \
}
+#define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes)
+
+#define FOR_EACH_C99_FEATURE(F) \
+ F(c_restrict) \
+ F(c_variadic_macros)
+
+#define FOR_EACH_C11_FEATURE(F) F(c_static_assert)
+
#define FOR_EACH_C_FEATURE(F) \
F(c_std_90) \
F(c_std_99) \
F(c_std_11) \
- F(c_function_prototypes) \
- F(c_restrict) \
- F(c_static_assert) \
- F(c_variadic_macros)
+ FOR_EACH_C90_FEATURE(F) \
+ FOR_EACH_C99_FEATURE(F) \
+ FOR_EACH_C11_FEATURE(F)
-#define FOR_EACH_CXX_FEATURE(F) \
- F(cxx_std_98) \
- F(cxx_std_11) \
- F(cxx_std_14) \
- F(cxx_std_17) \
- F(cxx_std_20) \
- F(cxx_aggregate_default_initializers) \
+#define FOR_EACH_CXX98_FEATURE(F) F(cxx_template_template_parameters)
+
+#define FOR_EACH_CXX11_FEATURE(F) \
F(cxx_alias_templates) \
F(cxx_alignas) \
F(cxx_alignof) \
F(cxx_attributes) \
- F(cxx_attribute_deprecated) \
F(cxx_auto_type) \
- F(cxx_binary_literals) \
F(cxx_constexpr) \
- F(cxx_contextual_conversions) \
F(cxx_decltype) \
- F(cxx_decltype_auto) \
F(cxx_decltype_incomplete_return_types) \
F(cxx_default_function_template_args) \
F(cxx_defaulted_functions) \
F(cxx_defaulted_move_initializers) \
F(cxx_delegating_constructors) \
F(cxx_deleted_functions) \
- F(cxx_digit_separators) \
F(cxx_enum_forward_declarations) \
F(cxx_explicit_conversions) \
F(cxx_extended_friend_declarations) \
@@ -603,11 +631,9 @@ private:
F(cxx_final) \
F(cxx_func_identifier) \
F(cxx_generalized_initializers) \
- F(cxx_generic_lambdas) \
F(cxx_inheriting_constructors) \
F(cxx_inline_namespaces) \
F(cxx_lambdas) \
- F(cxx_lambda_init_captures) \
F(cxx_local_type_template_args) \
F(cxx_long_long_type) \
F(cxx_noexcept) \
@@ -617,22 +643,41 @@ private:
F(cxx_range_for) \
F(cxx_raw_string_literals) \
F(cxx_reference_qualified_functions) \
- F(cxx_relaxed_constexpr) \
- F(cxx_return_type_deduction) \
F(cxx_right_angle_brackets) \
F(cxx_rvalue_references) \
F(cxx_sizeof_member) \
F(cxx_static_assert) \
F(cxx_strong_enums) \
- F(cxx_template_template_parameters) \
F(cxx_thread_local) \
F(cxx_trailing_return_types) \
F(cxx_unicode_literals) \
F(cxx_uniform_initialization) \
F(cxx_unrestricted_unions) \
F(cxx_user_literals) \
- F(cxx_variable_templates) \
F(cxx_variadic_macros) \
F(cxx_variadic_templates)
+#define FOR_EACH_CXX14_FEATURE(F) \
+ F(cxx_aggregate_default_initializers) \
+ F(cxx_attribute_deprecated) \
+ F(cxx_binary_literals) \
+ F(cxx_contextual_conversions) \
+ F(cxx_decltype_auto) \
+ F(cxx_digit_separators) \
+ F(cxx_generic_lambdas) \
+ F(cxx_lambda_init_captures) \
+ F(cxx_relaxed_constexpr) \
+ F(cxx_return_type_deduction) \
+ F(cxx_variable_templates)
+
+#define FOR_EACH_CXX_FEATURE(F) \
+ F(cxx_std_98) \
+ F(cxx_std_11) \
+ F(cxx_std_14) \
+ F(cxx_std_17) \
+ F(cxx_std_20) \
+ FOR_EACH_CXX98_FEATURE(F) \
+ FOR_EACH_CXX11_FEATURE(F) \
+ FOR_EACH_CXX14_FEATURE(F)
+
#endif
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a83f7dc8b..a6348b39e 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -23,6 +23,8 @@
# include "cmsys/ConsoleBuf.hxx"
#endif
+#include <cassert>
+#include <climits>
#include <ctype.h>
#include <iostream>
#include <string.h>
@@ -54,29 +56,38 @@ static const char* cmDocumentationUsageNote[][2] = {
# define CMAKE_BUILD_OPTIONS \
" <dir> = Project binary directory to be built.\n" \
- " -j [<jobs>] --parallel [<jobs>] = Build in parallel using\n" \
- " the given number of jobs. If <jobs> is omitted\n" \
- " the native build tool's default number is used.\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" \
+ " default number is used.\n" \
" The CMAKE_BUILD_PARALLEL_LEVEL environment " \
"variable\n" \
" specifies a default parallel level when this " \
"option\n" \
" is not given.\n" \
- " --target <tgt> = Build <tgt> instead of default targets.\n" \
- " May only be specified once.\n" \
+ " --target <tgt>..., -t <tgt>... \n" \
+ " = Build <tgt> instead of default targets.\n" \
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \
" --clean-first = Build target 'clean' first, then build.\n" \
" (To clean only, use --target 'clean'.)\n" \
- " --use-stderr = Ignored. Behavior is default in CMake >= 3.0.\n" \
- " -v --verbose = Enable verbose output - if supported - including\n" \
+ " --verbose, -v = Enable verbose output - if supported - including\n" \
" the build commands to be executed. \n" \
" -- = Pass remaining options to the native tool.\n"
+# define CMAKE_INSTALL_OPTIONS \
+ " <dir> = Project binary directory to install.\n" \
+ " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \
+ " --component <comp> = Component-based install. Only install <comp>.\n" \
+ " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n" \
+ " --strip = Performing install/strip.\n" \
+ " -v --verbose = Enable verbose output.\n"
+
static const char* cmDocumentationOptions[][2] = {
CMAKE_STANDARD_OPTIONS_TABLE,
{ "-E", "CMake command mode." },
{ "-L[A][H]", "List non-advanced cached variables." },
{ "--build <dir>", "Build a CMake-generated project binary tree." },
+ { "--install <dir>", "Install a CMake-generated project binary tree." },
{ "--open <dir>", "Open generated project in the associated application." },
{ "-N", "View mode only." },
{ "-P <file>", "Process script mode." },
@@ -85,6 +96,8 @@ static const char* cmDocumentationOptions[][2] = {
"Generate graphviz of dependencies, see "
"CMakeGraphVizOptions.cmake for more." },
{ "--system-information [file]", "Dump information about this system." },
+ { "--loglevel=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
+ "Set the verbosity of messages from CMake files." },
{ "--debug-trycompile",
"Do not delete the try_compile build tree. Only "
"useful on one try_compile at a time." },
@@ -109,12 +122,13 @@ static int do_command(int ac, char const* const* av)
std::vector<std::string> args;
args.reserve(ac - 1);
args.emplace_back(av[0]);
- args.insert(args.end(), av + 2, av + ac);
+ cmAppend(args, av + 2, av + ac);
return cmcmd::ExecuteCMakeCommand(args);
}
int do_cmake(int ac, char const* const* av);
static int do_build(int ac, char const* const* av);
+static int do_install(int ac, char const* const* av);
static int do_open(int ac, char const* const* av);
static cmMakefile* cmakemainGetMakefile(cmake* cm)
@@ -142,20 +156,21 @@ static std::string cmakemainGetStack(cmake* cm)
return msg;
}
-static void cmakemainMessageCallback(const char* m, const char* /*unused*/,
- cmake* cm)
+static void cmakemainMessageCallback(const std::string& m,
+ const char* /*unused*/, cmake* cm)
{
std::cerr << m << cmakemainGetStack(cm) << std::endl << std::flush;
}
-static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
+static void cmakemainProgressCallback(const std::string& m, float prog,
+ cmake* cm)
{
cmMakefile* mf = cmakemainGetMakefile(cm);
std::string dir;
- if ((mf) && (strstr(m, "Configuring") == m) && (prog < 0)) {
+ if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
dir = " ";
dir += mf->GetCurrentSourceDirectory();
- } else if ((mf) && (strstr(m, "Generating") == m)) {
+ } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
dir = " ";
dir += mf->GetCurrentBinaryDirectory();
}
@@ -169,6 +184,7 @@ static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
int main(int ac, char const* const* av)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
@@ -188,6 +204,9 @@ int main(int ac, char const* const* av)
if (strcmp(av[1], "--build") == 0) {
return do_build(ac, av);
}
+ if (strcmp(av[1], "--install") == 0) {
+ return do_install(ac, av);
+ }
if (strcmp(av[1], "--open") == 0) {
return do_open(ac, av);
}
@@ -319,10 +338,11 @@ int do_cmake(int ac, char const* const* av)
cmake cm(role, mode);
cm.SetHomeDirectory("");
cm.SetHomeOutputDirectory("");
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
- });
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
cm.SetWorkingMode(workingMode);
@@ -377,7 +397,14 @@ int extract_job_number(int& index, char const* current, char const* next,
if (jobString.empty()) {
jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
} else if (cmSystemTools::StringToULong(jobString.c_str(), &numJobs)) {
- jobs = int(numJobs);
+ if (numJobs == 0) {
+ std::cerr
+ << "The <jobs> value requires a positive integer argument.\n\n";
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The <jobs> value is too large.\n\n";
+ } else {
+ jobs = int(numJobs);
+ }
} else {
std::cerr << "'" << command.substr(0, len_of_flag) << "' invalid number '"
<< jobString << "' given.\n\n";
@@ -393,13 +420,14 @@ static int do_build(int ac, char const* const* av)
return -1;
#else
int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
- std::string target;
+ std::vector<std::string> targets;
std::string config = "Debug";
std::string dir;
std::vector<std::string> nativeOptions;
- bool clean = false;
+ bool cleanFirst = false;
+ bool foundClean = false;
+ bool foundNonClean = false;
bool verbose = cmSystemTools::HasEnv("VERBOSE");
- bool hasTarget = false;
enum Doing
{
@@ -419,25 +447,21 @@ static int do_build(int ac, char const* const* av)
if (jobs < 0) {
dir.clear();
}
+ 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();
}
- } else if (strcmp(av[i], "--target") == 0) {
- if (!hasTarget) {
- doing = DoingTarget;
- hasTarget = true;
- } else {
- std::cerr << "'--target' may not be specified more than once.\n\n";
- dir.clear();
- 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) {
- clean = true;
+ cleanFirst = true;
doing = DoingNone;
} else if ((strcmp(av[i], "--verbose") == 0) ||
(strcmp(av[i], "-v") == 0)) {
@@ -454,8 +478,23 @@ static int do_build(int ac, char const* const* av)
doing = DoingNone;
break;
case DoingTarget:
- target = av[i];
- doing = DoingNone;
+ 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];
@@ -477,7 +516,17 @@ static int do_build(int ac, char const* const* av)
} else {
unsigned long numJobs = 0;
if (cmSystemTools::StringToULong(parallel.c_str(), &numJobs)) {
- jobs = int(numJobs);
+ if (numJobs == 0) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "requires a positive integer argument.\n\n";
+ dir.clear();
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "is too large.\n\n";
+ dir.clear();
+ } else {
+ jobs = int(numJobs);
+ }
} else {
std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
<< "invalid number '" << parallel << "' given.\n\n";
@@ -499,13 +548,126 @@ static int do_build(int ac, char const* const* av)
}
cmake cm(cmake::RoleInternal, cmState::Project);
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
});
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ return cm.Build(jobs, dir, targets, config, nativeOptions, cleanFirst,
+ verbose);
+#endif
+}
+
+static int do_install(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+ std::cerr << "This cmake does not support --install\n";
+ return -1;
+#else
+ assert(1 < ac);
+
+ std::string config;
+ std::string component;
+ std::string prefix;
+ std::string dir;
+ bool strip = false;
+ bool verbose = cmSystemTools::HasEnv("VERBOSE");
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDir,
+ DoingConfig,
+ DoingComponent,
+ DoingPrefix,
+ };
+
+ Doing doing = DoingDir;
+
+ 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 {
+ 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;
+ default:
+ std::cerr << "Unknown argument " << av[i] << std::endl;
+ dir.clear();
+ break;
+ }
+ }
+ }
+
+ if (dir.empty()) {
+ std::cerr << "Usage: cmake --install <dir> "
+ "[options]\nOptions:\n" CMAKE_INSTALL_OPTIONS;
+ return 1;
+ }
+
+ cmake cm(cmake::RoleScript, cmState::Script);
+
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
- return cm.Build(jobs, dir, target, config, nativeOptions, clean, verbose);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.SetDebugOutputOn(verbose);
+ cm.SetWorkingMode(cmake::SCRIPT_MODE);
+
+ std::vector<std::string> args{ av[0] };
+
+ if (!prefix.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
+ }
+
+ if (!component.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
+ }
+
+ if (strip) {
+ args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
+ }
+
+ if (!config.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
+ }
+
+ args.emplace_back("-P");
+ args.emplace_back(dir + "/cmake_install.cmake");
+
+ return cm.Run(args) ? 1 : 0;
#endif
}
@@ -541,10 +703,11 @@ static int do_open(int ac, char const* const* av)
}
cmake cm(cmake::RoleInternal, cmState::Unknown);
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
- });
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
return cm.Open(dir, false) ? 0 : 1;
diff --git a/Source/cmakexbuild.cxx b/Source/cmakexbuild.cxx
deleted file mode 100644
index 295194595..000000000
--- a/Source/cmakexbuild.cxx
+++ /dev/null
@@ -1,80 +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" // IWYU pragma: keep
-
-#include "cmsys/Process.h"
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include "cmDuration.h"
-#include "cmSystemTools.h"
-
-// This is a wrapper program for xcodebuild
-// it calls xcodebuild, and does two things
-// it removes much of the output, all the setenv
-// stuff. Also, it checks for the text file busy
-// error, and re-runs xcodebuild until that error does
-// not show up.
-
-int RunXCode(std::vector<const char*>& argv, bool& hitbug)
-{
- hitbug = false;
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
- cmsysProcess_SetTimeout(cp, 0);
- cmsysProcess_Execute(cp);
- std::vector<char> out;
- std::vector<char> err;
- std::string line;
- int pipe =
- cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
- while (pipe != cmsysProcess_Pipe_None) {
- if (line.find("/bin/sh: bad interpreter: Text file busy") !=
- std::string::npos) {
- hitbug = true;
- std::cerr << "Hit xcodebuild bug : " << line << "\n";
- }
- // if the bug is hit, no more output should be generated
- // because it may contain bogus errors
- // also remove all output with setenv in it to tone down
- // the verbosity of xcodebuild
- if (!hitbug && (line.find("setenv") == std::string::npos)) {
- if (pipe == cmsysProcess_Pipe_STDERR) {
- std::cerr << line << "\n";
- } else if (pipe == cmsysProcess_Pipe_STDOUT) {
- std::cout << line << "\n";
- }
- }
- pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
- err);
- }
- cmsysProcess_WaitForExit(cp, nullptr);
- if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
- return cmsysProcess_GetExitValue(cp);
- }
- if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
- return -1;
- }
- return -1;
-}
-
-int main(int ac, char* av[])
-{
- std::vector<const char*> argv;
- argv.push_back("xcodebuild");
- for (int i = 1; i < ac; i++) {
- argv.push_back(av[i]);
- }
- argv.push_back(nullptr);
- bool hitbug = true;
- int ret = 0;
- while (hitbug) {
- ret = RunXCode(argv, hitbug);
- }
- if (ret < 0) {
- return 255;
- }
- return ret;
-}
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 1a10666c5..19d0d3843 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -276,7 +276,7 @@ int main()
std::string clrest = rest;
// rc: /fo x.dir\x.rc.res -> cl: /out:x.dir\x.rc.res.dep.obj
- clrest = replace(clrest, "/fo", "/out:");
+ clrest = replace(clrest, "/fo ", "/out:");
clrest = replace(clrest, objfile, objfile + ".dep.obj ");
cl = "\"" + cl + "\" /P /DRC_INVOKED /TC ";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index d20c5d23a..86082e517 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -7,8 +7,9 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
-#include "cmQtAutoGeneratorMocUic.h"
-#include "cmQtAutoGeneratorRcc.h"
+#include "cmQtAutoMocUic.h"
+#include "cmQtAutoRcc.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -37,6 +38,7 @@
#include "cmsys/Process.h"
#include "cmsys/Terminal.h"
#include <algorithm>
+#include <array>
#include <iostream>
#include <iterator>
#include <memory> // IWYU pragma: keep
@@ -101,7 +103,7 @@ void CMakeCommandUsage(const char* program)
<< " sha512sum <file>... - create SHA512 checksum of files\n"
<< " remove [-f] <file>... - remove the file(s), use -f to force "
"it\n"
- << " remove_directory dir - remove a directory and its contents\n"
+ << " remove_directory <dir>... - remove directories and their contents\n"
<< " rename oldname newname - rename a file or directory "
"(on one volume)\n"
<< " server - start cmake in server mode\n"
@@ -109,8 +111,8 @@ void CMakeCommandUsage(const char* program)
<< " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
<< " - create or extract a tar or zip archive\n"
<< " time command [args...] - run command and display elapsed time\n"
- << " touch file - touch a file.\n"
- << " touch_nocreate file - touch a file but do not create it.\n"
+ << " touch <file>... - touch a <file>.\n"
+ << " touch_nocreate <file>... - touch a <file> but do not create it.\n"
<< " create_symlink old new - create a symbolic link new -> old\n"
#if defined(_WIN32) && !defined(__CYGWIN__)
<< "Available on Windows only:\n"
@@ -171,7 +173,7 @@ static int HandleIWYU(const std::string& runCmd,
// and adding all the arguments we give to the compiler.
std::vector<std::string> iwyu_cmd;
cmSystemTools::ExpandListArgument(runCmd, iwyu_cmd, true);
- iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin() + 1, orig_cmd.end());
+ cmAppend(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
// Run the iwyu command line. Capture its stderr and hide its stdout.
// Ignore its return code because the tool always returns non-zero.
std::string stdErr;
@@ -199,11 +201,11 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
// automatically skip over the compiler itself and extract the
// options.
int ret;
- std::vector<std::string> tidy_cmd;
- cmSystemTools::ExpandListArgument(runCmd, tidy_cmd, true);
+ std::vector<std::string> tidy_cmd =
+ cmSystemTools::ExpandedListArgument(runCmd, true);
tidy_cmd.push_back(sourceFile);
tidy_cmd.emplace_back("--");
- tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin(), orig_cmd.end());
+ cmAppend(tidy_cmd, orig_cmd);
// Run the tidy command line. Capture its stdout and hide its stderr.
std::string stdOut;
@@ -350,12 +352,13 @@ struct CoCompiler
bool NoOriginalCommand;
};
-static CoCompiler CoCompilers[] = { // Table of options and handlers.
- { "--cppcheck=", HandleCppCheck, false },
- { "--cpplint=", HandleCppLint, false },
- { "--iwyu=", HandleIWYU, false },
- { "--lwyu=", HandleLWYU, true },
- { "--tidy=", HandleTidy, false }
+static const std::array<CoCompiler, 5> CoCompilers = {
+ { // Table of options and handlers.
+ { "--cppcheck=", HandleCppCheck, false },
+ { "--cpplint=", HandleCppLint, false },
+ { "--iwyu=", HandleIWYU, false },
+ { "--lwyu=", HandleLWYU, true },
+ { "--tidy=", HandleTidy, false } }
};
struct CoCompileJob
@@ -365,7 +368,7 @@ struct CoCompileJob
};
// called when args[0] == "__run_co_compile"
-int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
+int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
{
std::vector<CoCompileJob> jobs;
std::string sourceFile; // store --source=
@@ -378,24 +381,22 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
std::vector<std::string> orig_cmd;
bool doing_options = true;
- for (std::string::size_type i = 2; i < args.size(); ++i) {
- std::string const& arg = args[i];
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
// if the arg is -- then the rest of the args after
// go into orig_cmd
if (arg == "--") {
doing_options = false;
} else if (doing_options) {
bool optionFound = false;
- for (CoCompiler const* cc = cm::cbegin(CoCompilers);
- cc != cm::cend(CoCompilers); ++cc) {
- size_t optionLen = strlen(cc->Option);
- if (arg.compare(0, optionLen, cc->Option) == 0) {
+ for (CoCompiler const& cc : CoCompilers) {
+ size_t optionLen = strlen(cc.Option);
+ if (arg.compare(0, optionLen, cc.Option) == 0) {
optionFound = true;
CoCompileJob job;
job.Command = arg.substr(optionLen);
- job.Handler = cc->Handler;
+ job.Handler = cc.Handler;
jobs.push_back(std::move(job));
- if (cc->NoOriginalCommand) {
+ if (cc.NoOriginalCommand) {
runOriginalCmd = false;
}
}
@@ -419,9 +420,8 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
if (jobs.empty()) {
std::cerr << "__run_co_compile missing command to run. "
"Looking for one or more of the following:\n";
- for (CoCompiler const* cc = cm::cbegin(CoCompilers);
- cc != cm::cend(CoCompilers); ++cc) {
- std::cerr << cc->Option << "\n";
+ for (CoCompiler const& cc : CoCompilers) {
+ std::cerr << cc.Option << "\n";
}
return 1;
}
@@ -465,7 +465,7 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
return ret;
}
-int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
+int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
{
// IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
if (args.size() > 1) {
@@ -481,9 +481,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::cmCopyFile(args[cc], args.back())) {
- std::cerr << "Error copying file \"" << args[cc] << "\" to \""
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
+ std::cerr << "Error copying file \"" << arg << "\" to \""
<< args.back() << "\".\n";
return_value = true;
}
@@ -503,9 +503,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::CopyFileIfDifferent(args[cc], args.back())) {
- std::cerr << "Error copying file (if different) from \"" << args[cc]
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyFileIfDifferent(arg, args.back())) {
+ std::cerr << "Error copying file (if different) from \"" << arg
<< "\" to \"" << args.back() << "\".\n";
return_value = true;
}
@@ -517,10 +517,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
if (args[1] == "copy_directory" && args.size() > 3) {
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::CopyADirectory(args[cc], args.back())) {
- std::cerr << "Error copying directory from \"" << args[cc]
- << "\" to \"" << args.back() << "\".\n";
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyADirectory(arg, args.back())) {
+ std::cerr << "Error copying directory from \"" << arg << "\" to \""
+ << args.back() << "\".\n";
return_value = true;
}
}
@@ -613,13 +613,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
if (args[1] == "env") {
- std::vector<std::string>::const_iterator ai = args.begin() + 2;
- std::vector<std::string>::const_iterator ae = args.end();
+ auto ai = args.cbegin() + 2;
+ auto ae = args.cend();
for (; ai != ae; ++ai) {
std::string const& a = *ai;
if (cmHasLiteralPrefix(a, "--unset=")) {
// Unset environment variable.
- cmSystemTools::UnPutEnv(a.c_str() + 8);
+ cmSystemTools::UnPutEnv(a.substr(8));
} else if (!a.empty() && a[0] == '-') {
// Environment variable and command names cannot start in '-',
// so this must be an unknown option.
@@ -653,47 +653,49 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
#if defined(CMAKE_BUILD_WITH_CMAKE)
if (args[1] == "environment") {
- std::vector<std::string> env = cmSystemTools::GetEnvironmentVariables();
- std::vector<std::string>::iterator it;
- for (it = env.begin(); it != env.end(); ++it) {
- std::cout << *it << std::endl;
+ for (auto const& env : cmSystemTools::GetEnvironmentVariables()) {
+ std::cout << env << std::endl;
}
return 0;
}
#endif
if (args[1] == "make_directory" && args.size() > 2) {
- // If error occurs we want to continue copying next files.
+ // If an error occurs, we want to continue making directories.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::MakeDirectory(args[cc])) {
- std::cerr << "Error creating directory \"" << args[cc] << "\".\n";
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::MakeDirectory(arg)) {
+ std::cerr << "Error creating directory \"" << arg << "\".\n";
return_value = true;
}
}
return return_value;
}
- if (args[1] == "remove_directory" && args.size() == 3) {
- if (cmSystemTools::FileIsDirectory(args[2]) &&
- !cmSystemTools::RemoveADirectory(args[2])) {
- std::cerr << "Error removing directory \"" << args[2] << "\".\n";
- return 1;
+ if (args[1] == "remove_directory" && args.size() > 2) {
+ // If an error occurs, we want to continue removing directories.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (cmSystemTools::FileIsDirectory(arg) &&
+ !cmSystemTools::RemoveADirectory(arg)) {
+ std::cerr << "Error removing directory \"" << arg << "\".\n";
+ return_value = true;
+ }
}
- return 0;
+ return return_value;
}
// Remove file
if (args[1] == "remove" && args.size() > 2) {
bool force = false;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (args[cc] == "\\-f" || args[cc] == "-f") {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg == "\\-f" || arg == "-f") {
force = true;
} else {
// Complain if the file could not be removed, still exists,
// and the -f option was not given.
- if (!cmSystemTools::RemoveFile(args[cc]) && !force &&
- cmSystemTools::FileExists(args[cc])) {
+ if (!cmSystemTools::RemoveFile(arg) && !force &&
+ cmSystemTools::FileExists(arg)) {
return 1;
}
}
@@ -703,10 +705,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Touch file
if (args[1] == "touch" && args.size() > 2) {
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::Touch(args[cc], true)) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, true)) {
std::cerr << "cmake -E touch: failed to update \"";
- std::cerr << args[cc] << "\".\n";
+ std::cerr << arg << "\".\n";
return 1;
}
}
@@ -715,10 +717,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Touch file
if (args[1] == "touch_nocreate" && args.size() > 2) {
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::Touch(args[cc], false)) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, false)) {
std::cerr << "cmake -E touch_nocreate: failed to update \"";
- std::cerr << args[cc] << "\".\n";
+ std::cerr << arg << "\".\n";
return 1;
}
}
@@ -732,26 +734,22 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
cmake cm(cmake::RoleInternal, cmState::Unknown);
-#if defined(CMAKE_BUILD_WITH_CMAKE)
- std::cout << cm.ReportCapabilities(true);
-#else
- std::cout << cm.ReportCapabilities(false);
-#endif
+ std::cout << cm.ReportCapabilities();
return 0;
}
// Sleep command
if (args[1] == "sleep" && args.size() > 2) {
double total = 0;
- for (size_t i = 2; i < args.size(); ++i) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
double num = 0.0;
char unit;
char extra;
- int n = sscanf(args[i].c_str(), "%lg%c%c", &num, &unit, &extra);
+ int n = sscanf(arg.c_str(), "%lg%c%c", &num, &unit, &extra);
if ((n == 1 || (n == 2 && unit == 's')) && num >= 0) {
total += num;
} else {
- std::cerr << "Unknown sleep time format \"" << args[i] << "\".\n";
+ std::cerr << "Unknown sleep time format \"" << arg << "\".\n";
return 1;
}
}
@@ -817,8 +815,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
if (args[1] == "chdir" && args.size() >= 4) {
std::string const& directory = args[2];
if (!cmSystemTools::FileExists(directory)) {
- cmSystemTools::Error("Directory does not exist for chdir command: ",
- args[2].c_str());
+ cmSystemTools::Error("Directory does not exist for chdir command: " +
+ args[2]);
return 1;
}
@@ -826,7 +824,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
int retval = 0;
if (cmSystemTools::RunSingleCommand(
- command.c_str(), nullptr, nullptr, &retval, directory.c_str(),
+ command, nullptr, nullptr, &retval, directory.c_str(),
cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) {
return retval;
}
@@ -1020,13 +1018,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
#ifdef CMAKE_BUILD_WITH_CMAKE
if ((args[1] == "cmake_autogen") && (args.size() >= 4)) {
- cmQtAutoGeneratorMocUic autoGen;
+ cmQtAutoMocUic autoGen;
std::string const& infoDir = args[2];
std::string const& config = args[3];
return autoGen.Run(infoDir, config) ? 0 : 1;
}
if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
- cmQtAutoGeneratorRcc autoGen;
+ cmQtAutoRcc autoGen;
std::string const& infoFile = args[2];
std::string config;
if (args.size() > 3) {
@@ -1045,12 +1043,17 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::vector<std::string> files;
std::string mtime;
std::string format;
+ cmSystemTools::cmTarCompression compress =
+ cmSystemTools::TarCompressNone;
+ int nCompress = 0;
bool doing_options = true;
- for (std::string::size_type cc = 4; cc < args.size(); cc++) {
- std::string const& arg = args[cc];
+ for (auto const& arg : cmMakeRange(args).advance(4)) {
if (doing_options && cmHasLiteralPrefix(arg, "--")) {
if (arg == "--") {
doing_options = false;
+ } else if (arg == "--zstd") {
+ compress = cmSystemTools::TarCompressZstd;
+ ++nCompress;
} else if (cmHasLiteralPrefix(arg, "--mtime=")) {
mtime = arg.substr(8);
} else if (cmHasLiteralPrefix(arg, "--files-from=")) {
@@ -1065,37 +1068,60 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
format) != cm::cend(knownFormats);
if (!isKnown) {
- cmSystemTools::Error("Unknown -E tar --format= argument: ",
- format.c_str());
+ cmSystemTools::Error("Unknown -E tar --format= argument: " +
+ format);
return 1;
}
} else {
- cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str());
+ cmSystemTools::Error("Unknown option to -E tar: " + arg);
return 1;
}
} else {
files.push_back(arg);
}
}
- cmSystemTools::cmTarCompression compress =
- cmSystemTools::TarCompressNone;
+ cmSystemTools::cmTarAction action = cmSystemTools::TarActionNone;
bool verbose = false;
- int nCompress = 0;
- if (flags.find_first_of('j') != std::string::npos) {
- compress = cmSystemTools::TarCompressBZip2;
- ++nCompress;
- }
- if (flags.find_first_of('J') != std::string::npos) {
- compress = cmSystemTools::TarCompressXZ;
- ++nCompress;
- }
- if (flags.find_first_of('z') != std::string::npos) {
- compress = cmSystemTools::TarCompressGZip;
- ++nCompress;
+
+ for (auto flag : flags) {
+ switch (flag) {
+ case '-':
+ case 'f': {
+ // Keep for backward compatibility. Ignored
+ } break;
+ case 'j': {
+ compress = cmSystemTools::TarCompressBZip2;
+ ++nCompress;
+ } break;
+ case 'J': {
+ compress = cmSystemTools::TarCompressXZ;
+ ++nCompress;
+ } break;
+ case 'z': {
+ compress = cmSystemTools::TarCompressGZip;
+ ++nCompress;
+ } break;
+ case 'v': {
+ verbose = true;
+ } break;
+ case 't': {
+ action = cmSystemTools::TarActionList;
+ } break;
+ case 'c': {
+ action = cmSystemTools::TarActionCreate;
+ } break;
+ case 'x': {
+ action = cmSystemTools::TarActionExtract;
+ } break;
+ default: {
+ cmSystemTools::Message(
+ std::string("tar: Unknown argument: ") + flag, "Warning");
+ }
+ }
}
if ((format == "7zip" || format == "zip") && nCompress > 0) {
- cmSystemTools::Error("Can not use compression flags with format: ",
- format.c_str());
+ cmSystemTools::Error("Can not use compression flags with format: " +
+ format);
return 1;
}
if (nCompress > 1) {
@@ -1103,24 +1129,24 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
"at most one flag of z, j, or J may be used");
return 1;
}
- if (flags.find_first_of('v') != std::string::npos) {
- verbose = true;
- }
-
- if (flags.find_first_of('t') != std::string::npos) {
- if (!cmSystemTools::ListTar(outFile.c_str(), verbose)) {
- cmSystemTools::Error("Problem listing tar: ", outFile.c_str());
+ if (action == cmSystemTools::TarActionList) {
+ if (!cmSystemTools::ListTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem listing tar: " + outFile);
return 1;
}
- } else if (flags.find_first_of('c') != std::string::npos) {
- if (!cmSystemTools::CreateTar(outFile.c_str(), files, compress,
- verbose, mtime, format)) {
- cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
+ } else if (action == cmSystemTools::TarActionCreate) {
+ if (files.empty()) {
+ cmSystemTools::Message("tar: No files or directories specified",
+ "Warning");
+ }
+ if (!cmSystemTools::CreateTar(outFile, files, compress, verbose, mtime,
+ format)) {
+ cmSystemTools::Error("Problem creating tar: " + outFile);
return 1;
}
- } else if (flags.find_first_of('x') != std::string::npos) {
- if (!cmSystemTools::ExtractTar(outFile.c_str(), verbose)) {
- cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
+ } else if (action == cmSystemTools::TarActionExtract) {
+ if (!cmSystemTools::ExtractTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem extracting tar: " + outFile);
return 1;
}
#ifdef WIN32
@@ -1139,6 +1165,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
cmSystemTools::Delay(delay);
}
#endif
+ } else {
+ cmSystemTools::Error("tar: No action specified. Please choose: 't' "
+ "(list), 'c' (create) or 'x' (extract)");
+ return 1;
}
return 0;
}
@@ -1149,17 +1179,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
bool isDebug = false;
std::string pipe;
- for (size_t i = 2; i < args.size(); ++i) {
- const std::string& a = args[i];
-
- if (a == "--experimental") {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg == "--experimental") {
supportExperimental = true;
- } else if (a == "--debug") {
+ } else if (arg == "--debug") {
pipe.clear();
isDebug = true;
- } else if (a.substr(0, pipePrefix.size()) == pipePrefix) {
+ } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) {
isDebug = false;
- pipe = a.substr(pipePrefix.size());
+ pipe = arg.substr(pipePrefix.size());
if (pipe.empty()) {
cmSystemTools::Error("No pipe given after --pipe=");
return 2;
@@ -1231,15 +1259,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
-int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
+int cmcmd::HashSumFile(std::vector<std::string> const& args,
+ cmCryptoHash::Algo algo)
{
if (args.size() < 3) {
return -1;
}
int retval = 0;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- const char* filename = args[cc].c_str();
+ for (auto const& filename : cmMakeRange(args).advance(2)) {
// Cannot compute sum of a directory
if (cmSystemTools::FileIsDirectory(filename)) {
std::cerr << "Error: " << filename << " is a directory" << std::endl;
@@ -1258,7 +1286,7 @@ int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
return retval;
}
-int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
+int cmcmd::SymlinkLibrary(std::vector<std::string> const& args)
{
int result = 0;
std::string realName = args[2];
@@ -1282,7 +1310,7 @@ int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
return result;
}
-int cmcmd::SymlinkExecutable(std::vector<std::string>& args)
+int cmcmd::SymlinkExecutable(std::vector<std::string> const& args)
{
int result = 0;
std::string const& realName = args[2];
@@ -1356,7 +1384,7 @@ static void cmcmdProgressReport(std::string const& dir, std::string const& num)
}
}
-int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
+int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args)
{
// The arguments are
// args[0] == <cmake-executable>
@@ -1366,55 +1394,54 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
int color = cmsysTerminal_Color_Normal;
bool newline = true;
std::string progressDir;
- for (unsigned int i = 2; i < args.size(); ++i) {
- if (args[i].find("--switch=") == 0) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg.find("--switch=") == 0) {
// Enable or disable color based on the switch value.
- std::string value = args[i].substr(9);
+ std::string value = arg.substr(9);
if (!value.empty()) {
enabled = cmSystemTools::IsOn(value);
}
- } else if (cmHasLiteralPrefix(args[i], "--progress-dir=")) {
- progressDir = args[i].substr(15);
- } else if (cmHasLiteralPrefix(args[i], "--progress-num=")) {
+ } else if (cmHasLiteralPrefix(arg, "--progress-dir=")) {
+ progressDir = arg.substr(15);
+ } else if (cmHasLiteralPrefix(arg, "--progress-num=")) {
if (!progressDir.empty()) {
- std::string const& progressNum = args[i].substr(15);
+ std::string const& progressNum = arg.substr(15);
cmcmdProgressReport(progressDir, progressNum);
}
- } else if (args[i] == "--normal") {
+ } else if (arg == "--normal") {
color = cmsysTerminal_Color_Normal;
- } else if (args[i] == "--black") {
+ } else if (arg == "--black") {
color = cmsysTerminal_Color_ForegroundBlack;
- } else if (args[i] == "--red") {
+ } else if (arg == "--red") {
color = cmsysTerminal_Color_ForegroundRed;
- } else if (args[i] == "--green") {
+ } else if (arg == "--green") {
color = cmsysTerminal_Color_ForegroundGreen;
- } else if (args[i] == "--yellow") {
+ } else if (arg == "--yellow") {
color = cmsysTerminal_Color_ForegroundYellow;
- } else if (args[i] == "--blue") {
+ } else if (arg == "--blue") {
color = cmsysTerminal_Color_ForegroundBlue;
- } else if (args[i] == "--magenta") {
+ } else if (arg == "--magenta") {
color = cmsysTerminal_Color_ForegroundMagenta;
- } else if (args[i] == "--cyan") {
+ } else if (arg == "--cyan") {
color = cmsysTerminal_Color_ForegroundCyan;
- } else if (args[i] == "--white") {
+ } else if (arg == "--white") {
color = cmsysTerminal_Color_ForegroundWhite;
- } else if (args[i] == "--bold") {
+ } else if (arg == "--bold") {
color |= cmsysTerminal_Color_ForegroundBold;
- } else if (args[i] == "--no-newline") {
+ } else if (arg == "--no-newline") {
newline = false;
- } else if (args[i] == "--newline") {
+ } else if (arg == "--newline") {
newline = true;
} else {
// Color is enabled. Print with the current color.
- cmSystemTools::MakefileColorEcho(color, args[i].c_str(), newline,
- enabled);
+ cmSystemTools::MakefileColorEcho(color, arg.c_str(), newline, enabled);
}
}
return 0;
}
-int cmcmd::ExecuteLinkScript(std::vector<std::string>& args)
+int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
{
// The arguments are
// args[0] == <cmake-executable>
@@ -1627,9 +1654,9 @@ std::ostream& operator<<(std::ostream& stream,
return stream;
}
-static bool RunCommand(const char* comment, std::vector<std::string>& command,
- bool verbose, NumberFormat exitFormat,
- int* retCodeOut = nullptr,
+static bool RunCommand(const char* comment,
+ std::vector<std::string> const& command, bool verbose,
+ NumberFormat exitFormat, int* retCodeOut = nullptr,
bool (*retCodeOkay)(int) = nullptr)
{
if (verbose) {
@@ -1830,7 +1857,8 @@ int cmVSLink::LinkIncremental()
// Compile the resource file.
std::vector<std::string> rcCommand;
rcCommand.push_back(this->RcPath.empty() ? "rc" : this->RcPath);
- rcCommand.push_back("/fo" + this->ManifestFileRes);
+ rcCommand.emplace_back("/fo");
+ rcCommand.push_back(this->ManifestFileRes);
rcCommand.push_back(this->ManifestFileRC);
if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
return -1;
@@ -1894,8 +1922,7 @@ int cmVSLink::RunMT(std::string const& out, bool notify)
if (this->LinkGeneratesManifest) {
mtCommand.push_back(this->LinkerManifestFile);
}
- mtCommand.insert(mtCommand.end(), this->UserManifests.begin(),
- this->UserManifests.end());
+ cmAppend(mtCommand, this->UserManifests);
mtCommand.push_back(out);
if (notify) {
// Add an undocumented option that enables a special return
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
index d1e03d01f..69a7ecbb1 100644
--- a/Source/cmcmd.h
+++ b/Source/cmcmd.h
@@ -16,18 +16,18 @@ public:
* Execute commands during the build process. Supports options such
* as echo, remove file etc.
*/
- static int ExecuteCMakeCommand(std::vector<std::string>&);
+ static int ExecuteCMakeCommand(std::vector<std::string> const&);
protected:
- static int HandleCoCompileCommands(std::vector<std::string>& args);
- static int HashSumFile(std::vector<std::string>& args,
+ static int HandleCoCompileCommands(std::vector<std::string> const& args);
+ static int HashSumFile(std::vector<std::string> const& args,
cmCryptoHash::Algo algo);
- static int SymlinkLibrary(std::vector<std::string>& args);
- static int SymlinkExecutable(std::vector<std::string>& args);
+ static int SymlinkLibrary(std::vector<std::string> const& args);
+ static int SymlinkExecutable(std::vector<std::string> const& args);
static bool SymlinkInternal(std::string const& file,
std::string const& link);
- static int ExecuteEchoColor(std::vector<std::string>& args);
- static int ExecuteLinkScript(std::vector<std::string>& args);
+ static int ExecuteEchoColor(std::vector<std::string> const& args);
+ static int ExecuteLinkScript(std::vector<std::string> const& args);
static int WindowsCEEnvironment(const char* version,
const std::string& name);
static int VisualStudioLink(std::vector<std::string> const& args, int type);
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 4a2531a4e..3b3630fc9 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -143,6 +143,7 @@ static const char* cmDocumentationOptions[][2] = {
// this is a test driver program for cmCTest.
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
@@ -191,8 +192,7 @@ int main(int argc, char const* const* argv)
doc.addCTestStandardDocSections();
if (doc.CheckOptions(argc, argv)) {
// Construct and print requested documentation.
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(inst.GetHandler("script"));
+ cmCTestScriptHandler* ch = inst.GetScriptHandler();
ch->CreateCMake();
doc.SetShowGenerators(false);
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index e7da99462..79e813eef 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -120,7 +120,14 @@ SET_PROPERTY(DIRECTORY
if(KWSYS_CXX_STANDARD)
set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}")
elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD 11)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"
+ AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU"
+ )
+ set(CMAKE_CXX_STANDARD 14)
+ else()
+ set(CMAKE_CXX_STANDARD 11)
+ endif()
endif()
# Select library components.
@@ -172,6 +179,9 @@ ENDIF()
IF(KWSYS_USE_Directory)
SET(KWSYS_USE_Encoding 1)
ENDIF()
+IF(KWSYS_USE_DynamicLoader)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
IF(KWSYS_USE_FStream)
SET(KWSYS_USE_Encoding 1)
ENDIF()
@@ -179,13 +189,6 @@ IF(KWSYS_USE_ConsoleBuf)
SET(KWSYS_USE_Encoding 1)
ENDIF()
-# Setup the large file support default.
-IF(KWSYS_LFS_DISABLE)
- SET(KWSYS_LFS_REQUESTED 0)
-ELSE()
- SET(KWSYS_LFS_REQUESTED 1)
-ENDIF()
-
# Specify default 8 bit encoding for Windows
IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
@@ -353,30 +356,6 @@ IF(KWSYS_STANDALONE)
ENDIF()
#-----------------------------------------------------------------------------
-# Configure Large File Support.
-KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDIO
- "Checking whether header cstdio is available" DIRECT)
-SET(KWSYS_LFS_AVAILABLE 0)
-IF(KWSYS_LFS_REQUESTED)
- # Large File Support is requested.
- SET(KWSYS_LFS_REQUESTED 1)
-
- # Check for large file support.
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES
- -DKWSYS_CXX_HAS_CSTDIO=${KWSYS_CXX_HAS_CSTDIO})
- KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_LFS_WORKS
- "Checking for Large File Support" DIRECT)
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
-
- IF(KWSYS_LFS_WORKS)
- SET(KWSYS_LFS_AVAILABLE 1)
- ENDIF()
-ELSE()
- # Large File Support is not requested.
- SET(KWSYS_LFS_REQUESTED 0)
-ENDIF()
-
-#-----------------------------------------------------------------------------
# Configure the standard library header wrappers based on compiler's
# capabilities and parent project's request. Enforce 0/1 as only
# possible values for configuration into Configure.hxx.
@@ -493,6 +472,14 @@ IF(KWSYS_USE_DynamicLoader)
ENDIF()
IF(KWSYS_USE_SystemTools)
+ if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ endif ()
+ if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ else ()
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
+ endif ()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
"Checking whether CXX compiler has setenv" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
@@ -575,9 +562,6 @@ IF(KWSYS_USE_SystemInformation)
COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
ENDIF()
ENDIF()
- IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE)
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1)
- ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
"Checking whether CXX compiler has rlimit64" DIRECT)
SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
@@ -917,6 +901,11 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
IF(KWSYS_USE_SystemInformation)
IF(WIN32)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32)
+ # link in dbghelp.dll for symbol lookup if MSVC 1800 or later
+ # Note that the dbghelp runtime is part of MS Windows OS
+ IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800)
+ TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp)
+ ENDIF()
IF(KWSYS_SYS_HAS_PSAPI)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
Psapi)
@@ -1023,7 +1012,8 @@ ENDIF()
ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
# Disable deprecation warnings for standard C functions.
-IF(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel"))
+IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR
+ (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))))
ADD_DEFINITIONS(
-D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_SECURE_NO_DEPRECATE
@@ -1130,6 +1120,20 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
+
+ if (WIN32)
+ # Windows tests supported flags.
+ add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
+ add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
+ endif ()
ENDIF()
CREATE_TEST_SOURCELIST(
KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
index 31115e51f..7db901556 100644
--- a/Source/kwsys/CommandLineArguments.hxx.in
+++ b/Source/kwsys/CommandLineArguments.hxx.in
@@ -62,6 +62,9 @@ public:
CommandLineArguments();
~CommandLineArguments();
+ CommandLineArguments(const CommandLineArguments&) = delete;
+ CommandLineArguments& operator=(const CommandLineArguments&) = delete;
+
/**
* Various argument types.
*/
diff --git a/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in
index bec1abca4..5323c57be 100644
--- a/Source/kwsys/Configure.h.in
+++ b/Source/kwsys/Configure.h.in
@@ -28,43 +28,6 @@
/* Whether kwsys namespace is "kwsys". */
#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@
-/* Whether Large File Support is requested. */
-#define @KWSYS_NAMESPACE@_LFS_REQUESTED @KWSYS_LFS_REQUESTED@
-
-/* Whether Large File Support is available. */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-# define @KWSYS_NAMESPACE@_LFS_AVAILABLE @KWSYS_LFS_AVAILABLE@
-#endif
-
-/* Setup Large File Support if requested. */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-/* Since LFS is requested this header must be included before system
- headers whether or not LFS is available. */
-# if 0 && (defined(_SYS_TYPES_H) || defined(_SYS_TYPES_INCLUDED))
-# error "@KWSYS_NAMESPACE@/Configure.h must be included before sys/types.h"
-# endif
-/* Enable the large file API if it is available. */
-# if @KWSYS_NAMESPACE@_LFS_AVAILABLE && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINES)
-# if !defined(_LARGEFILE_SOURCE) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE_SOURCE)
-# define _LARGEFILE_SOURCE
-# endif
-# if !defined(_LARGEFILE64_SOURCE) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE64_SOURCE)
-# define _LARGEFILE64_SOURCE
-# endif
-# if !defined(_LARGE_FILES) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGE_FILES)
-# define _LARGE_FILES
-# endif
-# if !defined(_FILE_OFFSET_BITS) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS)
-# define _FILE_OFFSET_BITS 64
-# endif
-# endif
-#endif
-
/* Setup the export macro. */
#if @KWSYS_BUILD_SHARED@
# if defined(_WIN32) || defined(__CYGWIN__)
diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
index d1e7464ff..92ffea3c9 100644
--- a/Source/kwsys/Configure.hxx.in
+++ b/Source/kwsys/Configure.hxx.in
@@ -11,6 +11,9 @@
/* Whether <ext/stdio_filebuf.h> is available. */
#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@
+/* Whether the translation map is available or not. */
+#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \
+ @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@
#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute)
# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x)
@@ -56,6 +59,8 @@
@KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH
# define KWSYS_NULLPTR @KWSYS_NAMESPACE@_NULLPTR
+# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \
+ @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
#endif
#endif
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 31b1c15d0..59530a43f 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -102,7 +102,7 @@ bool Directory::Load(const std::string& name)
# endif
char* buf;
size_t n = name.size();
- if (*name.rbegin() == '/' || *name.rbegin() == '\\') {
+ if (name.back() == '/' || name.back() == '\\') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
@@ -144,7 +144,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
# endif
char* buf;
size_t n = name.size();
- if (*name.rbegin() == '/') {
+ if (name.back() == '/') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
index a85690f7c..b93a215cc 100644
--- a/Source/kwsys/DynamicLoader.cxx
+++ b/Source/kwsys/DynamicLoader.cxx
@@ -1,9 +1,14 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#if defined(_WIN32)
+# define NOMINMAX // hide min,max to not conflict with <limits>
+#endif
+
#include "kwsysPrivate.h"
#include KWSYS_HEADER(DynamicLoader.hxx)
#include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
@@ -25,6 +30,28 @@
// Each part of the ifdef contains a complete implementation for
// the static methods of DynamicLoader.
+#define CHECK_OPEN_FLAGS(var, supported, ret) \
+ do { \
+ /* Check for unknown flags. */ \
+ if ((var & AllOpenFlags) != var) { \
+ return ret; \
+ } \
+ \
+ /* Check for unsupported flags. */ \
+ if ((var & (supported)) != var) { \
+ return ret; \
+ } \
+ } while (0)
+
+namespace KWSYS_NAMESPACE {
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ return DynamicLoader::OpenLibrary(libname, 0);
+}
+}
+
#if !KWSYS_SUPPORTS_SHARED_LIBS
// Implementation for environments without dynamic libs
# include <string.h> // for strerror()
@@ -32,7 +59,7 @@
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
return 0;
}
@@ -67,8 +94,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
}
@@ -130,8 +159,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
NSObjectFileImageReturnCode rc;
NSObjectFileImage image = 0;
@@ -185,19 +216,22 @@ const char* DynamicLoader::LastError()
// Implementation for Windows win32 code but not cygwin
# include <windows.h>
+# include <stdio.h>
+
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
- DynamicLoader::LibraryHandle lh;
- int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
- wchar_t* wchars = new wchar_t[length + 1];
- wchars[0] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
- lh = LoadLibraryW(wchars);
- delete[] wchars;
- return lh;
+ CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, NULL);
+
+ DWORD llFlags = 0;
+ if (flags & SearchBesideLibrary) {
+ llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
+ }
+
+ return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), NULL,
+ llFlags);
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
@@ -247,24 +281,38 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
# endif
}
+# define DYNLOAD_ERROR_BUFFER_SIZE 1024
+
const char* DynamicLoader::LastError()
{
- LPVOID lpMsgBuf = NULL;
-
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR)&lpMsgBuf, 0, NULL);
+ wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+ DWORD error = GetLastError();
+ DWORD length = FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, NULL);
+
+ static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+ if (length < 1) {
+ /* FormatMessage failed. Use a default message. */
+ _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+ "DynamicLoader encountered error 0x%X. "
+ "FormatMessage failed with error 0x%X",
+ error, GetLastError());
+ return str;
+ }
- if (!lpMsgBuf) {
- return NULL;
+ if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
+ DYNLOAD_ERROR_BUFFER_SIZE, NULL, NULL)) {
+ /* WideCharToMultiByte failed. Use a default message. */
+ _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+ "DynamicLoader encountered error 0x%X. "
+ "WideCharToMultiByte failed with error 0x%X",
+ error, GetLastError());
}
- static char* str = 0;
- delete[] str;
- str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
- // Free the buffer.
- LocalFree(lpMsgBuf);
return str;
}
@@ -282,8 +330,10 @@ namespace KWSYS_NAMESPACE {
static image_id last_dynamic_err = B_OK;
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
// image_id's are integers, errors are negative. Add one just in case we
// get a valid image_id of zero (is that even possible?).
image_id rc = load_add_on(libname.c_str());
@@ -360,8 +410,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, NULL);
+
char* name = (char*)calloc(1, libname.size() + 1);
dld_init(program_invocation_name);
strncpy(name, libname.c_str(), libname.size());
@@ -404,8 +456,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, NULL);
+
return dlopen(libname.c_str(), RTLD_LAZY);
}
diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
index 08f2790af..539c74259 100644
--- a/Source/kwsys/DynamicLoader.hxx.in
+++ b/Source/kwsys/DynamicLoader.hxx.in
@@ -66,10 +66,23 @@ public:
// Return type from DynamicLoader::GetSymbolAddress.
typedef void (*SymbolPointer)();
+ enum OpenFlags
+ {
+ // Search for dependent libraries beside the library being loaded.
+ //
+ // This is currently only supported on Windows.
+ SearchBesideLibrary = 0x00000001,
+
+ AllOpenFlags = SearchBesideLibrary
+ };
+
/** Load a dynamic library into the current process.
* The returned LibraryHandle can be used to access the symbols in the
- * library. */
+ * library. The optional second argument is a set of flags to use when
+ * opening the library. If unrecognized or unsupported flags are specified,
+ * the library is not opened. */
static LibraryHandle OpenLibrary(const std::string&);
+ static LibraryHandle OpenLibrary(const std::string&, int);
/** Attempt to detach a dynamic library from the
* process. A value of true is returned if it is successful. */
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 6952d24ae..829c1389f 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -263,7 +263,7 @@ bool Glob::RecurseDirectory(std::string::size_type start,
}
} else {
if (!this->Internals->Expressions.empty() &&
- this->Internals->Expressions.rbegin()->find(fname)) {
+ this->Internals->Expressions.back().find(fname)) {
this->AddFile(this->Internals->Files, realname);
}
}
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index bd4a17616..4c3bde167 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -41,17 +41,9 @@ public:
, content(c)
{
}
- Message(const Message& msg)
- : type(msg.type)
- , content(msg.content)
- {
- }
- Message& operator=(Message const& msg)
- {
- this->type = msg.type;
- this->content = msg.content;
- return *this;
- }
+ ~Message() = default;
+ Message(const Message& msg) = default;
+ Message& operator=(Message const& msg) = default;
};
typedef std::vector<Message> GlobMessages;
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 2a2e73761..68c52185e 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -117,7 +117,6 @@ static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
kwsysProcessTime in2);
-static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
int idx);
static void kwsysProcessKillTree(int pid);
@@ -358,13 +357,20 @@ kwsysProcess* kwsysProcess_New(void)
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
#endif
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
#endif
if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
/* Win9x no longer supported. */
@@ -2269,13 +2275,20 @@ static kwsysProcess_List* kwsysProcess_List_New(void)
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
#endif
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
#endif
self->NT4 =
(osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1
@@ -2659,8 +2672,8 @@ static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4;
/* Try allocating the new block of memory. */
- if (newArray = (kwsysProcessInstance*)malloc(
- newSize * sizeof(kwsysProcessInstance))) {
+ if ((newArray = (kwsysProcessInstance*)malloc(
+ newSize * sizeof(kwsysProcessInstance)))) {
/* Copy the old process handles to the new memory. */
if (kwsysProcesses.Count > 0) {
memcpy(newArray, kwsysProcesses.Processes,
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index f323efc4b..7dc6cf4b0 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -2,6 +2,9 @@
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#if defined(_WIN32)
# define NOMINMAX // use our min,max
+# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800
+# define _WIN32_WINNT 0x0600 // vista
+# endif
# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
# define _WIN32_WINNT 0x0501
# endif
@@ -444,6 +447,7 @@ public:
IBM,
Motorola,
HP,
+ Hygon,
UnknownManufacturer
};
@@ -1766,6 +1770,8 @@ const char* SystemInformationImplementation::GetVendorID()
return "Motorola";
case HP:
return "Hewlett-Packard";
+ case Hygon:
+ return "Chengdu Haiguang IC Design Co., Ltd.";
case UnknownManufacturer:
default:
return "Unknown Manufacturer";
@@ -2117,6 +2123,8 @@ void SystemInformationImplementation::FindManufacturer(
this->ChipManufacturer = AMD; // Advanced Micro Devices
else if (this->ChipID.Vendor == "AMD ISBETTER")
this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
+ else if (this->ChipID.Vendor == "HygonGenuine")
+ this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd.
else if (this->ChipID.Vendor == "CyrixInstead")
this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
else if (this->ChipID.Vendor == "NexGenDriven")
@@ -2751,7 +2759,7 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
0); // MP Capable -- > Bit 19.
// Retrieve AMD specific extended features.
- if (this->ChipManufacturer == AMD) {
+ if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) {
this->Features.ExtendedFeatures.HasMMXPlus =
((localCPUExtendedFeatures[3] & 0x00400000) !=
0); // AMD specific: MMX-SSE --> Bit 22
@@ -3158,6 +3166,10 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
}
break;
+ case Hygon:
+ this->ChipID.ProcessorName = "Unknown Hygon family";
+ return false;
+
case Transmeta:
switch (this->ChipID.Family) {
case 5:
@@ -3880,34 +3892,78 @@ SystemInformation::LongLong SystemInformationImplementation::GetProcessId()
}
/**
+ * Used in GetProgramStack(...) below
+ */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \
+ _MSC_VER >= 1800
+# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
+# define TRACE_MAX_STACK_FRAMES 1024
+# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
+# pragma warning(push)
+# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */
+# include "dbghelp.h"
+# pragma warning(pop)
+#endif
+
+/**
return current program stack in a string
demangle cxx symbols if possible.
*/
std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
int wholePath)
{
- std::string programStack = ""
-#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
- "WARNING: The stack could not be examined "
- "because backtrace is not supported.\n"
-#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
- "WARNING: The stack trace will not use advanced "
- "capabilities because this is a release build.\n"
+ std::ostringstream oss;
+ std::string programStack = "";
+
+#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
+ (void)wholePath;
+
+ void* stack[TRACE_MAX_STACK_FRAMES];
+ HANDLE process = GetCurrentProcess();
+ SymInitialize(process, NULL, TRUE);
+ WORD numberOfFrames =
+ CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, NULL);
+ SYMBOL_INFO* symbol = static_cast<SYMBOL_INFO*>(
+ malloc(sizeof(SYMBOL_INFO) +
+ (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR)));
+ symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ DWORD displacement;
+ IMAGEHLP_LINE64 line;
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+ for (int i = 0; i < numberOfFrames; i++) {
+ DWORD64 address = reinterpret_cast<DWORD64>(stack[i]);
+ SymFromAddr(process, address, NULL, symbol);
+ if (SymGetLineFromAddr64(process, address, &displacement, &line)) {
+ oss << " at " << symbol->Name << " in " << line.FileName << " line "
+ << line.LineNumber << std::endl;
+ } else {
+ oss << " at " << symbol->Name << std::endl;
+ }
+ }
+ free(symbol);
+
#else
-# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
- "WARNING: Function names will not be demangled "
- "because "
- "dladdr is not available.\n"
-# endif
-# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
- "WARNING: Function names will not be demangled "
- "because cxxabi is not available.\n"
+ programStack += ""
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+ "WARNING: The stack could not be examined "
+ "because backtrace is not supported.\n"
+# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
+ "WARNING: The stack trace will not use advanced "
+ "capabilities because this is a release build.\n"
+# else
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+ "WARNING: Function names will not be demangled "
+ "because dladdr is not available.\n"
+# endif
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+ "WARNING: Function names will not be demangled "
+ "because cxxabi is not available.\n"
+# endif
# endif
-#endif
;
- std::ostringstream oss;
-#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
void* stackSymbols[256];
int nFrames = backtrace(stackSymbols, 256);
for (int i = firstFrame; i < nFrames; ++i) {
@@ -3916,10 +3972,12 @@ std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
symProps.Initialize(stackSymbols[i]);
oss << symProps << std::endl;
}
-#else
+# else
(void)firstFrame;
(void)wholePath;
+# endif
#endif
+
programStack += oss.str();
return programStack;
@@ -4620,7 +4678,7 @@ std::string SystemInformationImplementation::RunProcess(
// Run the application
kwsysProcess* gp = kwsysProcess_New();
- kwsysProcess_SetCommand(gp, &*args.begin());
+ kwsysProcess_SetCommand(gp, args.data());
kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1);
kwsysProcess_Execute(gp);
@@ -5147,6 +5205,9 @@ bool SystemInformationImplementation::QueryOSInformation()
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
@@ -5159,7 +5220,11 @@ bool SystemInformationImplementation::QueryOSInformation()
}
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
switch (osvi.dwPlatformId) {
diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
index 9e1ce6ce2..5e93878fa 100644
--- a/Source/kwsys/SystemInformation.hxx.in
+++ b/Source/kwsys/SystemInformation.hxx.in
@@ -56,6 +56,9 @@ public:
SystemInformation();
~SystemInformation();
+ SystemInformation(const SystemInformation&) = delete;
+ SystemInformation& operator=(const SystemInformation&) = delete;
+
const char* GetVendorString();
const char* GetVendorID();
std::string GetTypeID();
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index d8904fed7..2135913f5 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -28,6 +28,7 @@
#include <iostream>
#include <set>
#include <sstream>
+#include <utility>
#include <vector>
// Work-around CMake dependency scanning limitation. This must
@@ -363,10 +364,6 @@ double SystemTools::GetTime(void)
#endif
}
-class SystemToolsTranslationMap : public std::map<std::string, std::string>
-{
-};
-
/* Type of character storing the environment. */
#if defined(_WIN32)
typedef wchar_t envchar;
@@ -416,6 +413,9 @@ public:
{
}
~Free() { free(const_cast<envchar*>(this->Env)); }
+
+ Free(const Free&) = delete;
+ Free& operator=(const Free&) = delete;
};
const envchar* Release(const envchar* env)
@@ -444,15 +444,141 @@ struct SystemToolsPathCaseCmp
# endif
}
};
+#endif
-class SystemToolsPathCaseMap
- : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
+/**
+ * SystemTools static variables singleton class.
+ */
+class SystemToolsStatic
{
+public:
+ typedef std::map<std::string, std::string> StringMap;
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
+ /**
+ * Path translation table from dir to refdir
+ * Each time 'dir' will be found it will be replace by 'refdir'
+ */
+ StringMap TranslationMap;
+#endif
+#ifdef _WIN32
+ static std::string GetCasePathName(std::string const& pathIn);
+ static std::string GetActualCaseForPathCached(std::string const& path);
+ static const char* GetEnvBuffered(const char* key);
+ std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
+ std::map<std::string, std::string> EnvMap;
+#endif
+#ifdef __CYGWIN__
+ StringMap Cyg2Win32Map;
+#endif
+
+ /**
+ * Actual implementation of ReplaceString.
+ */
+ static void ReplaceString(std::string& source, const char* replace,
+ size_t replaceSize, const std::string& with);
+
+ /**
+ * Actual implementation of FileIsFullPath.
+ */
+ static bool FileIsFullPath(const char*, size_t);
+
+ /**
+ * Find a filename (file or directory) in the system PATH, with
+ * optional extra paths.
+ */
+ static std::string FindName(
+ const std::string& name,
+ const std::vector<std::string>& path = std::vector<std::string>(),
+ bool no_system_path = false);
};
-class SystemToolsEnvMap : public std::map<std::string, std::string>
+#ifdef _WIN32
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
{
-};
+ std::string casePath;
+
+ // First check if the file is relative. We don't fix relative paths since the
+ // real case depends on the root directory and the given path fragment may
+ // have meaning elsewhere in the project.
+ if (!SystemTools::FileIsFullPath(pathIn)) {
+ // This looks unnecessary, but it allows for the return value optimization
+ // since all return paths return the same local variable.
+ casePath = pathIn;
+ return casePath;
+ }
+
+ std::vector<std::string> path_components;
+ SystemTools::SplitPath(pathIn, path_components);
+
+ // Start with root component.
+ std::vector<std::string>::size_type idx = 0;
+ casePath = path_components[idx++];
+ // make sure drive letter is always upper case
+ if (casePath.size() > 1 && casePath[1] == ':') {
+ casePath[0] = toupper(casePath[0]);
+ }
+ const char* sep = "";
+
+ // If network path, fill casePath with server/share so FindFirstFile
+ // will work after that. Maybe someday call other APIs to get
+ // actual case of servers and shares.
+ if (path_components.size() > 2 && path_components[0] == "//") {
+ casePath += path_components[idx++];
+ casePath += "/";
+ casePath += path_components[idx++];
+ sep = "/";
+ }
+
+ // Convert case of all components that exist.
+ bool converting = true;
+ for (; idx < path_components.size(); idx++) {
+ casePath += sep;
+ sep = "/";
+
+ if (converting) {
+ // If path component contains wildcards, we skip matching
+ // because these filenames are not allowed on windows,
+ // and we do not want to match a different file.
+ if (path_components[idx].find('*') != std::string::npos ||
+ path_components[idx].find('?') != std::string::npos) {
+ converting = false;
+ } else {
+ std::string test_str = casePath;
+ test_str += path_components[idx];
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind =
+ ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+ if (INVALID_HANDLE_VALUE != hFind) {
+ path_components[idx] = Encoding::ToNarrow(findData.cFileName);
+ ::FindClose(hFind);
+ } else {
+ converting = false;
+ }
+ }
+ }
+
+ casePath += path_components[idx];
+ }
+ return casePath;
+}
+
+std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
+{
+ // Check to see if actual case has already been called
+ // for this path, and the result is stored in the PathCaseMap
+ auto& pcm = SystemTools::Statics->PathCaseMap;
+ {
+ auto itr = pcm.find(p);
+ if (itr != pcm.end()) {
+ return itr->second;
+ }
+ }
+ std::string casePath = SystemToolsStatic::GetCasePathName(p);
+ if (casePath.size() <= MAX_PATH) {
+ pcm[p] = casePath;
+ }
+ return casePath;
+}
#endif
// adds the elements of the env variable path to the arg passed in
@@ -473,7 +599,7 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
}
// A hack to make the below algorithm work.
- if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) {
+ if (!pathEnv.empty() && pathEnv.back() != pathSep) {
pathEnv += pathSep;
}
std::string::size_type start = 0;
@@ -493,30 +619,37 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
}
}
-const char* SystemTools::GetEnvImpl(const char* key)
-{
- const char* v = KWSYS_NULLPTR;
#if defined(_WIN32)
+const char* SystemToolsStatic::GetEnvBuffered(const char* key)
+{
std::string env;
if (SystemTools::GetEnv(key, env)) {
- std::string& menv = (*SystemTools::EnvMap)[key];
- menv = env;
- v = menv.c_str();
+ std::string& menv = SystemTools::Statics->EnvMap[key];
+ if (menv != env) {
+ menv = std::move(env);
+ }
+ return menv.c_str();
}
-#else
- v = getenv(key);
-#endif
- return v;
+ return KWSYS_NULLPTR;
}
+#endif
const char* SystemTools::GetEnv(const char* key)
{
- return SystemTools::GetEnvImpl(key);
+#if defined(_WIN32)
+ return SystemToolsStatic::GetEnvBuffered(key);
+#else
+ return getenv(key);
+#endif
}
const char* SystemTools::GetEnv(const std::string& key)
{
- return SystemTools::GetEnvImpl(key.c_str());
+#if defined(_WIN32)
+ return SystemToolsStatic::GetEnvBuffered(key.c_str());
+#else
+ return getenv(key.c_str());
+#endif
}
bool SystemTools::GetEnv(const char* key, std::string& result)
@@ -819,7 +952,8 @@ void SystemTools::ReplaceString(std::string& source,
return;
}
- SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
+ SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(),
+ with);
}
void SystemTools::ReplaceString(std::string& source, const char* replace,
@@ -830,12 +964,13 @@ void SystemTools::ReplaceString(std::string& source, const char* replace,
return;
}
- SystemTools::ReplaceString(source, replace, strlen(replace),
- with ? with : "");
+ SystemToolsStatic::ReplaceString(source, replace, strlen(replace),
+ with ? with : "");
}
-void SystemTools::ReplaceString(std::string& source, const char* replace,
- size_t replaceSize, const std::string& with)
+void SystemToolsStatic::ReplaceString(std::string& source, const char* replace,
+ size_t replaceSize,
+ const std::string& with)
{
const char* src = source.c_str();
char* searchPos = const_cast<char*>(strstr(src, replace));
@@ -1313,18 +1448,16 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf)
#ifdef __CYGWIN__
bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
{
- SystemToolsTranslationMap::iterator i =
- SystemTools::Cyg2Win32Map->find(path);
-
- if (i != SystemTools::Cyg2Win32Map->end()) {
- strncpy(win32_path, i->second.c_str(), MAX_PATH);
+ auto itr = SystemTools::Statics->Cyg2Win32Map.find(path);
+ if (itr != SystemTools::Statics->Cyg2Win32Map.end()) {
+ strncpy(win32_path, itr->second.c_str(), MAX_PATH);
} else {
if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) !=
0) {
win32_path[0] = 0;
}
- SystemToolsTranslationMap::value_type entry(path, win32_path);
- SystemTools::Cyg2Win32Map->insert(entry);
+ SystemTools::Statics->Cyg2Win32Map.insert(
+ SystemToolsStatic::StringMap::value_type(path, win32_path));
}
return win32_path[0] != 0;
}
@@ -1943,7 +2076,7 @@ void SystemTools::ConvertToUnixSlashes(std::string& path)
// a single /
pathCString = path.c_str();
size_t size = path.size();
- if (size > 1 && *path.rbegin() == '/') {
+ if (size > 1 && path.back() == '/') {
// if it is c:/ then do not remove the trailing slash
if (!((size == 3 && pathCString[1] == ':'))) {
path.resize(size - 1);
@@ -2670,9 +2803,9 @@ size_t SystemTools::GetMaximumFilePathLength()
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
-std::string SystemTools::FindName(const std::string& name,
- const std::vector<std::string>& userPaths,
- bool no_system_path)
+std::string SystemToolsStatic::FindName(
+ const std::string& name, const std::vector<std::string>& userPaths,
+ bool no_system_path)
{
// Add the system search path to our path first
std::vector<std::string> path;
@@ -2681,27 +2814,15 @@ std::string SystemTools::FindName(const std::string& name,
SystemTools::GetPath(path);
}
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
- // Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// now look for the file
std::string tryPath;
- for (std::vector<std::string>::const_iterator p = path.begin();
- p != path.end(); ++p) {
- tryPath = *p;
+ for (std::string const& p : path) {
+ tryPath = p;
+ if (tryPath.empty() || tryPath.back() != '/') {
+ tryPath += '/';
+ }
tryPath += name;
if (SystemTools::FileExists(tryPath)) {
return tryPath;
@@ -2720,7 +2841,8 @@ std::string SystemTools::FindFile(const std::string& name,
const std::vector<std::string>& userPaths,
bool no_system_path)
{
- std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+ std::string tryPath =
+ SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2737,7 +2859,8 @@ std::string SystemTools::FindDirectory(
const std::string& name, const std::vector<std::string>& userPaths,
bool no_system_path)
{
- std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+ std::string tryPath =
+ SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2773,14 +2896,13 @@ std::string SystemTools::FindProgram(const std::string& name,
// the end of it
// on windows try .com then .exe
if (name.size() <= 3 || name[name.size() - 4] != '.') {
- extensions.push_back(".com");
- extensions.push_back(".exe");
+ extensions.emplace_back(".com");
+ extensions.emplace_back(".exe");
// first try with extensions if the os supports them
- for (std::vector<std::string>::iterator i = extensions.begin();
- i != extensions.end(); ++i) {
+ for (std::string const& ext : extensions) {
tryPath = name;
- tryPath += *i;
+ tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2799,43 +2921,33 @@ std::string SystemTools::FindProgram(const std::string& name,
SystemTools::GetPath(path);
}
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
+ for (std::string& p : path) {
+ if (p.empty() || p.back() != '/') {
+ p += '/';
}
}
// Try each path
- for (std::vector<std::string>::iterator p = path.begin(); p != path.end();
- ++p) {
+ for (std::string& p : path) {
#ifdef _WIN32
// Remove double quotes from the path on windows
- SystemTools::ReplaceString(*p, "\"", "");
+ SystemTools::ReplaceString(p, "\"", "");
#endif
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
// first try with extensions
- for (std::vector<std::string>::iterator ext = extensions.begin();
- ext != extensions.end(); ++ext) {
- tryPath = *p;
+ for (std::string const& ext : extensions) {
+ tryPath = p;
tryPath += name;
- tryPath += *ext;
+ tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
}
#endif
// now try it without them
- tryPath = *p;
+ tryPath = p;
tryPath += name;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
@@ -2849,10 +2961,9 @@ std::string SystemTools::FindProgram(const std::vector<std::string>& names,
const std::vector<std::string>& path,
bool noSystemPath)
{
- for (std::vector<std::string>::const_iterator it = names.begin();
- it != names.end(); ++it) {
+ for (std::string const& name : names) {
// Try to find the program.
- std::string result = SystemTools::FindProgram(*it, path, noSystemPath);
+ std::string result = SystemTools::FindProgram(name, path, noSystemPath);
if (!result.empty()) {
return result;
}
@@ -2877,27 +2988,18 @@ std::string SystemTools::FindLibrary(const std::string& name,
std::vector<std::string> path;
SystemTools::GetPath(path);
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
+ for (std::string& p : path) {
+ if (p.empty() || p.back() != '/') {
+ p += '/';
}
}
std::string tryPath;
- for (std::vector<std::string>::const_iterator p = path.begin();
- p != path.end(); ++p) {
+ for (std::string const& p : path) {
#if defined(__APPLE__)
- tryPath = *p;
+ tryPath = p;
tryPath += name;
tryPath += ".framework";
if (SystemTools::FileIsDirectory(tryPath)) {
@@ -2905,42 +3007,42 @@ std::string SystemTools::FindLibrary(const std::string& name,
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
- tryPath = *p;
+ tryPath = p;
tryPath += name;
tryPath += ".lib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
#else
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".so";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".a";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".sl";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dylib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dll";
@@ -3202,9 +3304,8 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut,
msg << " argv[0] = \"" << argv0 << "\"\n";
}
msg << " Attempted paths:\n";
- std::vector<std::string>::iterator i;
- for (i = failures.begin(); i != failures.end(); ++i) {
- msg << " \"" << *i << "\"\n";
+ for (std::string const& ff : failures) {
+ msg << " \"" << ff << "\"\n";
}
errorMsg = msg.str();
return false;
@@ -3218,6 +3319,7 @@ std::string SystemTools::CollapseFullPath(const std::string& in_relative)
return SystemTools::CollapseFullPath(in_relative, KWSYS_NULLPTR);
}
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
void SystemTools::AddTranslationPath(const std::string& a,
const std::string& b)
{
@@ -3234,15 +3336,16 @@ void SystemTools::AddTranslationPath(const std::string& a,
if (SystemTools::FileIsFullPath(path_b) &&
path_b.find("..") == std::string::npos) {
// Before inserting make sure path ends with '/'
- if (!path_a.empty() && *path_a.rbegin() != '/') {
+ if (!path_a.empty() && path_a.back() != '/') {
path_a += '/';
}
- if (!path_b.empty() && *path_b.rbegin() != '/') {
+ if (!path_b.empty() && path_b.back() != '/') {
path_b += '/';
}
if (!(path_a == path_b)) {
- SystemTools::TranslationMap->insert(
- SystemToolsTranslationMap::value_type(path_a, path_b));
+ SystemTools::Statics->TranslationMap.insert(
+ SystemToolsStatic::StringMap::value_type(std::move(path_a),
+ std::move(path_b)));
}
}
}
@@ -3266,22 +3369,21 @@ void SystemTools::CheckTranslationPath(std::string& path)
// Always add a trailing slash before translation. It does not
// matter if this adds an extra slash, but we do not want to
// translate part of a directory (like the foo part of foo-dir).
- path += "/";
+ path += '/';
// In case a file was specified we still have to go through this:
// Now convert any path found in the table back to the one desired:
- std::map<std::string, std::string>::const_iterator it;
- for (it = SystemTools::TranslationMap->begin();
- it != SystemTools::TranslationMap->end(); ++it) {
+ for (auto const& pair : SystemTools::Statics->TranslationMap) {
// We need to check of the path is a substring of the other path
- if (path.find(it->first) == 0) {
- path = path.replace(0, it->first.size(), it->second);
+ if (path.find(pair.first) == 0) {
+ path = path.replace(0, pair.first.size(), pair.second);
}
}
// Remove the trailing slash we added before.
- path.erase(path.end() - 1, path.end());
+ path.pop_back();
}
+#endif
static void SystemToolsAppendComponents(
std::vector<std::string>& out_components,
@@ -3352,6 +3454,7 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path,
// Transform the path back to a string.
std::string newPath = SystemTools::JoinPath(out_components);
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Update the translation table with this potentially new path. I am not
// sure why this line is here, it seems really questionable, but yet I
// would put good money that if I remove it something will break, basically
@@ -3367,8 +3470,9 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path,
// SystemTools::AddTranslationPath(newPath, in_path);
SystemTools::CheckTranslationPath(newPath);
+#endif
#ifdef _WIN32
- newPath = SystemTools::GetActualCaseForPathCached(newPath);
+ newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath);
SystemTools::ConvertToUnixSlashes(newPath);
#endif
// Return the reconstructed path.
@@ -3428,130 +3532,39 @@ std::string SystemTools::RelativePath(const std::string& local,
// for each entry that is not common in the local path
// add a ../ to the finalpath array, this gets us out of the local
// path into the remote dir
- for (unsigned int i = 0; i < localSplit.size(); ++i) {
- if (!localSplit[i].empty()) {
- finalPath.push_back("../");
+ for (std::string const& lp : localSplit) {
+ if (!lp.empty()) {
+ finalPath.emplace_back("../");
}
}
// for each entry that is not common in the remote path add it
// to the final path.
- for (std::vector<std::string>::iterator vit = remoteSplit.begin();
- vit != remoteSplit.end(); ++vit) {
- if (!vit->empty()) {
- finalPath.push_back(*vit);
+ for (std::string const& rp : remoteSplit) {
+ if (!rp.empty()) {
+ finalPath.push_back(rp);
}
}
std::string relativePath; // result string
// now turn the array of directories into a unix path by puttint /
// between each entry that does not already have one
- for (std::vector<std::string>::iterator vit1 = finalPath.begin();
- vit1 != finalPath.end(); ++vit1) {
- if (!relativePath.empty() && *relativePath.rbegin() != '/') {
- relativePath += "/";
+ for (std::string const& fp : finalPath) {
+ if (!relativePath.empty() && relativePath.back() != '/') {
+ relativePath += '/';
}
- relativePath += *vit1;
+ relativePath += fp;
}
return relativePath;
}
-#ifdef _WIN32
-static std::string GetCasePathName(std::string const& pathIn)
-{
- std::string casePath;
-
- // First check if the file is relative. We don't fix relative paths since the
- // real case depends on the root directory and the given path fragment may
- // have meaning elsewhere in the project.
- if (!SystemTools::FileIsFullPath(pathIn)) {
- // This looks unnecessary, but it allows for the return value optimization
- // since all return paths return the same local variable.
- casePath = pathIn;
- return casePath;
- }
-
- std::vector<std::string> path_components;
- SystemTools::SplitPath(pathIn, path_components);
-
- // Start with root component.
- std::vector<std::string>::size_type idx = 0;
- casePath = path_components[idx++];
- // make sure drive letter is always upper case
- if (casePath.size() > 1 && casePath[1] == ':') {
- casePath[0] = toupper(casePath[0]);
- }
- const char* sep = "";
-
- // If network path, fill casePath with server/share so FindFirstFile
- // will work after that. Maybe someday call other APIs to get
- // actual case of servers and shares.
- if (path_components.size() > 2 && path_components[0] == "//") {
- casePath += path_components[idx++];
- casePath += "/";
- casePath += path_components[idx++];
- sep = "/";
- }
-
- // Convert case of all components that exist.
- bool converting = true;
- for (; idx < path_components.size(); idx++) {
- casePath += sep;
- sep = "/";
-
- if (converting) {
- // If path component contains wildcards, we skip matching
- // because these filenames are not allowed on windows,
- // and we do not want to match a different file.
- if (path_components[idx].find('*') != std::string::npos ||
- path_components[idx].find('?') != std::string::npos) {
- converting = false;
- } else {
- std::string test_str = casePath;
- test_str += path_components[idx];
- WIN32_FIND_DATAW findData;
- HANDLE hFind =
- ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
- if (INVALID_HANDLE_VALUE != hFind) {
- path_components[idx] = Encoding::ToNarrow(findData.cFileName);
- ::FindClose(hFind);
- } else {
- converting = false;
- }
- }
- }
-
- casePath += path_components[idx];
- }
- return casePath;
-}
-#endif
-
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
-#ifndef _WIN32
- return p;
+#ifdef _WIN32
+ return SystemToolsStatic::GetCasePathName(p);
#else
- return GetCasePathName(p);
+ return p;
#endif
}
-#ifdef _WIN32
-std::string SystemTools::GetActualCaseForPathCached(std::string const& p)
-{
- // Check to see if actual case has already been called
- // for this path, and the result is stored in the PathCaseMap
- SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p);
- if (i != SystemTools::PathCaseMap->end()) {
- return i->second;
- }
- std::string casePath = GetCasePathName(p);
- if (casePath.size() > MAX_PATH) {
- return casePath;
- }
- (*SystemTools::PathCaseMap)[p] = casePath;
- return casePath;
-}
-#endif
-
const char* SystemTools::SplitPathRootComponent(const std::string& p,
std::string* root)
{
@@ -3648,7 +3661,7 @@ void SystemTools::SplitPath(const std::string& p,
}
#endif
if (!homedir.empty() &&
- (*homedir.rbegin() == '/' || *homedir.rbegin() == '\\')) {
+ (homedir.back() == '/' || homedir.back() == '\\')) {
homedir.resize(homedir.size() - 1);
}
SystemTools::SplitPath(homedir, components);
@@ -3686,8 +3699,7 @@ std::string SystemTools::JoinPath(
// Construct result in a single string.
std::string result;
size_t len = 0;
- std::vector<std::string>::const_iterator i;
- for (i = first; i != last; ++i) {
+ for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
len += 1 + i->size();
}
result.reserve(len);
@@ -4016,7 +4028,7 @@ bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
filename_dir = SystemTools::GetFilenamePath(filename_dir);
filename_dir_base = SystemTools::GetFilenameName(filename_dir);
#if defined(_WIN32)
- if (filename_dir_base.empty() || *filename_dir_base.rbegin() == ':')
+ if (filename_dir_base.empty() || filename_dir_base.back() == ':')
#else
if (filename_dir_base.empty())
#endif
@@ -4044,16 +4056,16 @@ bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
bool SystemTools::FileIsFullPath(const std::string& in_name)
{
- return SystemTools::FileIsFullPath(in_name.c_str(), in_name.size());
+ return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(const char* in_name)
{
- return SystemTools::FileIsFullPath(in_name,
- in_name[0] ? (in_name[1] ? 2 : 1) : 0);
+ return SystemToolsStatic::FileIsFullPath(
+ in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
-bool SystemTools::FileIsFullPath(const char* in_name, size_t len)
+bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
{
#if defined(_WIN32) || defined(__CYGWIN__)
// On Windows, the name must be at least two characters long.
@@ -4092,7 +4104,7 @@ bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
std::string tempPath = path; // create a buffer
// if the path passed in has quotes around it, first remove the quotes
- if (!path.empty() && path[0] == '"' && *path.rbegin() == '"') {
+ if (!path.empty() && path[0] == '"' && path.back() == '"') {
tempPath = path.substr(1, path.length() - 2);
}
@@ -4169,7 +4181,7 @@ bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
bool haveData = !line.empty() || !is.eof();
if (!line.empty()) {
// Avoid storing a carriage return character.
- if (*line.rbegin() == '\r') {
+ if (line.back() == '\r') {
line.resize(line.size() - 1);
}
@@ -4307,7 +4319,7 @@ bool SystemTools::IsSubDirectory(const std::string& cSubdir,
if (subdir.size() <= dir.size() || dir.empty()) {
return false;
}
- bool isRootPath = *dir.rbegin() == '/'; // like "/" or "C:/"
+ bool isRootPath = dir.back() == '/'; // like "/" or "C:/"
size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size();
if (subdir[expectedSlashPosition] != '/') {
return false;
@@ -4354,6 +4366,9 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
@@ -4363,7 +4378,11 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
return 0;
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
switch (osvi.dwPlatformId) {
@@ -4651,14 +4670,7 @@ bool SystemTools::ParseURL(const std::string& URL, std::string& protocol,
// These must NOT be initialized. Default initialization to zero is
// necessary.
static unsigned int SystemToolsManagerCount;
-SystemToolsTranslationMap* SystemTools::TranslationMap;
-#ifdef _WIN32
-SystemToolsPathCaseMap* SystemTools::PathCaseMap;
-SystemToolsEnvMap* SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
-SystemToolsTranslationMap* SystemTools::Cyg2Win32Map;
-#endif
+SystemToolsStatic* SystemTools::Statics;
// SystemToolsManager manages the SystemTools singleton.
// SystemToolsManager should be included in any translation unit
@@ -4699,20 +4711,15 @@ void SystemTools::ClassInitialize()
#ifdef __VMS
SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
#endif
- // Allocate the translation map first.
- SystemTools::TranslationMap = new SystemToolsTranslationMap;
-#ifdef _WIN32
- SystemTools::PathCaseMap = new SystemToolsPathCaseMap;
- SystemTools::EnvMap = new SystemToolsEnvMap;
-#endif
-#ifdef __CYGWIN__
- SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
-#endif
+ // Create statics singleton instance
+ SystemTools::Statics = new SystemToolsStatic;
+
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Add some special translation paths for unix. These are not added
// for windows because drive letters need to be maintained. Also,
// there are not sym-links and mount points on windows anyway.
-#if !defined(_WIN32) || defined(__CYGWIN__)
+# if !defined(_WIN32) || defined(__CYGWIN__)
// The tmp path is frequently a logical path so always keep it:
SystemTools::AddKeepPath("/tmp/");
@@ -4750,19 +4757,13 @@ void SystemTools::ClassInitialize()
}
}
}
+# endif
#endif
}
void SystemTools::ClassFinalize()
{
- delete SystemTools::TranslationMap;
-#ifdef _WIN32
- delete SystemTools::PathCaseMap;
- delete SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
- delete SystemTools::Cyg2Win32Map;
-#endif
+ delete SystemTools::Statics;
}
} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index 1967860ab..dd1266bee 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -41,9 +41,7 @@ typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
namespace @KWSYS_NAMESPACE@ {
-class SystemToolsTranslationMap;
-class SystemToolsPathCaseMap;
-class SystemToolsEnvMap;
+class SystemToolsStatic;
/** \class SystemToolsManager
* \brief Use to make sure SystemTools is initialized before it is used
@@ -54,6 +52,9 @@ class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager
public:
SystemToolsManager();
~SystemToolsManager();
+
+ SystemToolsManager(const SystemToolsManager&) = delete;
+ SystemToolsManager& operator=(const SystemToolsManager&) = delete;
};
// This instance will show up in any translation unit that uses
@@ -890,6 +891,7 @@ public:
*/
static int GetTerminalWidth();
+#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
/**
* Add an entry in the path translation table.
*/
@@ -906,6 +908,7 @@ public:
* Update path by going through the Path Translation table;
*/
static void CheckTranslationPath(std::string& path);
+#endif
/**
* Delay the execution for a specified amount of time specified
@@ -964,41 +967,8 @@ private:
return &SystemToolsManagerInstance;
}
- /**
- * Actual implementation of ReplaceString.
- */
- static void ReplaceString(std::string& source, const char* replace,
- size_t replaceSize, const std::string& with);
-
- /**
- * Actual implementation of FileIsFullPath.
- */
- static bool FileIsFullPath(const char*, size_t);
-
- /**
- * Find a filename (file or directory) in the system PATH, with
- * optional extra paths.
- */
- static std::string FindName(
- const std::string& name,
- const std::vector<std::string>& path = std::vector<std::string>(),
- bool no_system_path = false);
-
- static const char* GetEnvImpl(const char* key);
-
- /**
- * Path translation table from dir to refdir
- * Each time 'dir' will be found it will be replace by 'refdir'
- */
- static SystemToolsTranslationMap* TranslationMap;
-#ifdef _WIN32
- static std::string GetActualCaseForPathCached(std::string const& path);
- static SystemToolsPathCaseMap* PathCaseMap;
- static SystemToolsEnvMap* EnvMap;
-#endif
-#ifdef __CYGWIN__
- static SystemToolsTranslationMap* Cyg2Win32Map;
-#endif
+ static SystemToolsStatic* Statics;
+ friend class SystemToolsStatic;
friend class SystemToolsManager;
};
diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in
index fc0d60e7d..0981c66ff 100644
--- a/Source/kwsys/hashtable.hxx.in
+++ b/Source/kwsys/hashtable.hxx.in
@@ -73,7 +73,7 @@ struct _Hashtable_node
void public_method_to_quiet_warning_about_all_methods_private();
private:
- void operator=(_Hashtable_node<_Val> const&); // poison node assignment
+ void operator=(_Hashtable_node<_Val> const&) = delete;
};
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
index b77d7292a..cfd5666f3 100644
--- a/Source/kwsys/kwsysPlatformTestsCXX.cxx
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
@@ -136,42 +136,6 @@ int main()
}
#endif
-#ifdef TEST_KWSYS_LFS_WORKS
-/* Return 0 when LFS is available and 1 otherwise. */
-# define _LARGEFILE_SOURCE
-# define _LARGEFILE64_SOURCE
-# define _LARGE_FILES
-# define _FILE_OFFSET_BITS 64
-# include <sys/types.h>
-
-# include <assert.h>
-# include <sys/stat.h>
-# if KWSYS_CXX_HAS_CSTDIO
-# include <cstdio>
-# endif
-# include <stdio.h>
-
-int main(int, char** argv)
-{
-/* check that off_t can hold 2^63 - 1 and perform basic operations... */
-# define OFF_T_64 (((off_t)1 << 62) - 1 + ((off_t)1 << 62))
- if (OFF_T_64 % 2147483647 != 1)
- return 1;
-
- // stat breaks on SCO OpenServer
- struct stat buf;
- stat(argv[0], &buf);
- if (!S_ISREG(buf.st_mode))
- return 2;
-
- FILE* file = fopen(argv[0], "r");
- off_t offset = ftello(file);
- fseek(file, offset, SEEK_CUR);
- fclose(file);
- return 0;
-}
-#endif
-
#ifdef TEST_KWSYS_CXX_HAS_SETENV
# include <stdlib.h>
int main()
@@ -212,12 +176,6 @@ int main()
#endif
#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64
-# if defined(KWSYS_HAS_LFS)
-# define _LARGEFILE_SOURCE
-# define _LARGEFILE64_SOURCE
-# define _LARGE_FILES
-# define _FILE_OFFSET_BITS 64
-# endif
# include <sys/resource.h>
int main()
{
diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx
index 154944058..b6ad1188d 100644
--- a/Source/kwsys/testConsoleBuf.cxx
+++ b/Source/kwsys/testConsoleBuf.cxx
@@ -499,6 +499,9 @@ static int testConsole()
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
@@ -506,7 +509,11 @@ static int testConsole()
const bool isVistaOrGreater =
LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
if (!isVistaOrGreater) {
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
index ce87117a1..eff2ed7ee 100644
--- a/Source/kwsys/testDynamicLoader.cxx
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -21,11 +21,15 @@
// left on disk.
#include <testSystemTools.h>
-static std::string GetLibName(const char* lname)
+static std::string GetLibName(const char* lname, const char* subdir = NULL)
{
// Construct proper name of lib
std::string slname;
slname = EXECUTABLE_OUTPUT_PATH;
+ if (subdir) {
+ slname += "/";
+ slname += subdir;
+ }
#ifdef CMAKE_INTDIR
slname += "/";
slname += CMAKE_INTDIR;
@@ -45,26 +49,29 @@ static std::string GetLibName(const char* lname)
* r3: should CloseLibrary succeed ?
*/
static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
- int r2, int r3)
+ int r2, int r3, int flags = 0)
{
std::cerr << "Testing: " << libname << std::endl;
kwsys::DynamicLoader::LibraryHandle l =
- kwsys::DynamicLoader::OpenLibrary(libname);
+ kwsys::DynamicLoader::OpenLibrary(libname, flags);
// If result is incompatible with expectation just fails (xor):
if ((r1 && !l) || (!r1 && l)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
kwsys::DynamicLoader::SymbolPointer f =
kwsys::DynamicLoader::GetSymbolAddress(l, symbol);
if ((r2 && !f) || (!r2 && f)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
#ifndef __APPLE__
int s = kwsys::DynamicLoader::CloseLibrary(l);
if ((r3 && !s) || (!r3 && s)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
#else
@@ -113,5 +120,14 @@ int testDynamicLoader(int argc, char* argv[])
res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
+#ifdef _WIN32
+ libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir");
+ res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0);
+ res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1,
+ kwsys::DynamicLoader::SearchBesideLibrary);
+ res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1,
+ kwsys::DynamicLoader::SearchBesideLibrary);
+#endif
+
return res;
}
diff --git a/Source/kwsys/testDynloadImpl.c b/Source/kwsys/testDynloadImpl.c
new file mode 100644
index 000000000..2b9069bc7
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.c
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+
+#include "testDynloadImpl.h"
+
+int TestDynamicLoaderImplData = 0;
+
+void TestDynamicLoaderImplSymbolPointer()
+{
+}
diff --git a/Source/kwsys/testDynloadImpl.h b/Source/kwsys/testDynloadImpl.h
new file mode 100644
index 000000000..d0c9dfb75
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#ifdef _WIN32
+# ifdef BUILDING_TestDynloadImpl
+# define DLIMPL_EXPORT __declspec(dllexport)
+# else
+# define DLIMPL_EXPORT __declspec(dllimport)
+# endif
+#else
+# define DLIMPL_EXPORT
+#endif
+
+DLIMPL_EXPORT int TestDynamicLoaderImplData;
+
+DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer();
diff --git a/Source/kwsys/testDynloadUse.c b/Source/kwsys/testDynloadUse.c
new file mode 100644
index 000000000..5402add6a
--- /dev/null
+++ b/Source/kwsys/testDynloadUse.c
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#include "testDynloadImpl.h"
+
+#ifdef _WIN32
+# define DL_EXPORT __declspec(dllexport)
+#else
+# define DL_EXPORT
+#endif
+
+DL_EXPORT int TestLoad()
+{
+ TestDynamicLoaderImplSymbolPointer();
+ return TestDynamicLoaderImplData;
+}
diff --git a/Tests/AliasTarget/CMakeLists.txt b/Tests/AliasTarget/CMakeLists.txt
index fc7013598..627198810 100644
--- a/Tests/AliasTarget/CMakeLists.txt
+++ b/Tests/AliasTarget/CMakeLists.txt
@@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 98)
# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
- set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD 14)
endif()
add_library(foo SHARED empty.cpp)
diff --git a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
index 7dc799525..a5bc1e1b3 100644
--- a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
@@ -34,6 +34,7 @@ target_compile_definitions(consumer
CONSUMER_LANG_$<COMPILE_LANGUAGE>
LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
LANG_IS_C=$<COMPILE_LANGUAGE:C>
+ LANG_IS_C_OR_CXX=$<COMPILE_LANGUAGE:C,CXX>
)
if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
target_compile_definitions(consumer
diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.c b/Tests/CMakeCommands/target_compile_definitions/consumer.c
index bacd4c402..bb65e011b 100644
--- a/Tests/CMakeCommands/target_compile_definitions/consumer.c
+++ b/Tests/CMakeCommands/target_compile_definitions/consumer.c
@@ -35,6 +35,10 @@
# endif
#endif
+#if !LANG_IS_C_OR_CXX
+# error Expected LANG_IS_C_OR_CXX
+#endif
+
void consumer_c()
{
}
diff --git a/Tests/CMakeCommands/target_compile_options/CMakeLists.txt b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
index 1dedbae82..a7055b157 100644
--- a/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
@@ -7,9 +7,11 @@ add_executable(target_compile_options
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
)
target_compile_options(target_compile_options
- PRIVATE $<$<CXX_COMPILER_ID:GNU>:-DMY_PRIVATE_DEFINE>
- PUBLIC $<$<CXX_COMPILER_ID:GNU>:-DMY_PUBLIC_DEFINE>
+ PRIVATE $<$<CXX_COMPILER_ID:AppleClang,Clang,GNU>:-DMY_PRIVATE_DEFINE>
+ PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-DMY_PUBLIC_DEFINE>
+ PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>:-DMY_MUTLI_COMP_PUBLIC_DEFINE>
INTERFACE $<$<CXX_COMPILER_ID:GNU>:-DMY_INTERFACE_DEFINE>
+ INTERFACE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-DMY_MULTI_COMP_INTERFACE_DEFINE>
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -17,6 +19,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
PRIVATE
"DO_GNU_TESTS"
)
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ target_compile_definitions(target_compile_options
+ PRIVATE
+ "DO_CLANG_TESTS"
+ )
endif()
add_executable(consumer
@@ -40,7 +47,7 @@ if(CMAKE_GENERATOR MATCHES "Visual Studio")
endif()
target_compile_options(consumer
- PRIVATE $<$<CXX_COMPILER_ID:GNU>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
+ PRIVATE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -48,6 +55,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
PRIVATE
"DO_GNU_TESTS"
)
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ target_compile_definitions(consumer
+ PRIVATE
+ "DO_CLANG_TESTS"
+ )
endif()
# Test no items
diff --git a/Tests/CMakeCommands/target_compile_options/consumer.cpp b/Tests/CMakeCommands/target_compile_options/consumer.cpp
index fe79eb551..78928b42e 100644
--- a/Tests/CMakeCommands/target_compile_options/consumer.cpp
+++ b/Tests/CMakeCommands/target_compile_options/consumer.cpp
@@ -13,6 +13,30 @@
# error Expected MY_INTERFACE_DEFINE
# endif
+# ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+# error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+#endif
+
+#ifdef DO_CLANG_TESTS
+
+# ifdef MY_PRIVATE_DEFINE
+# error Unexpected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+# error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
#endif
#ifndef CONSUMER_LANG_CXX
diff --git a/Tests/CMakeCommands/target_compile_options/main.cpp b/Tests/CMakeCommands/target_compile_options/main.cpp
index 829a25e73..7608400c4 100644
--- a/Tests/CMakeCommands/target_compile_options/main.cpp
+++ b/Tests/CMakeCommands/target_compile_options/main.cpp
@@ -9,12 +9,32 @@
# error Expected MY_PUBLIC_DEFINE
# endif
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
# ifdef MY_INTERFACE_DEFINE
# error Unexpected MY_INTERFACE_DEFINE
# endif
#endif
+#ifdef DO_CLANG_TESTS
+
+# ifndef MY_PRIVATE_DEFINE
+# error Expected MY_PRIVATE_DEFINE
+# endif
+
+# ifdef MY_PUBLIC_DEFINE
+# error Unexpected MY_PUBLIC_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+#endif
+
int main()
{
return 0;
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index f6a9153f9..a25f25af0 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -5,18 +5,26 @@ include_directories(
)
set(CMakeLib_TESTS
+ testArgumentParser.cxx
testGeneratedFileStream.cxx
testRST.cxx
+ testRange.cxx
testString.cxx
testSystemTools.cxx
testUTF8.cxx
testXMLParser.cxx
testXMLSafe.cxx
testFindPackageCommand.cxx
+ testUVProcessChain.cxx
testUVRAII.cxx
+ testUVStreambuf.cxx
)
+add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
+
set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
+set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>)
+set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>)
if(WIN32)
list(APPEND CMakeLib_TESTS
@@ -41,7 +49,7 @@ target_link_libraries(testEncoding cmsys)
foreach(testfile ${CMakeLib_TESTS})
get_filename_component(test "${testfile}" NAME_WE)
- add_test(CMakeLib.${test} CMakeLibTests ${test} ${${test}_ARGS})
+ add_test(NAME CMakeLib.${test} COMMAND CMakeLibTests ${test} ${${test}_ARGS})
endforeach()
if(TEST_CompileCommandOutput)
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
new file mode 100644
index 000000000..788fecee6
--- /dev/null
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -0,0 +1,148 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmArgumentParser.h"
+
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
+
+#include <initializer_list>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace {
+
+struct Result
+{
+ bool Option1 = false;
+ bool Option2 = false;
+
+ std::string String1;
+ std::string String2;
+
+ std::vector<std::string> List1;
+ std::vector<std::string> List2;
+ std::vector<std::string> List3;
+
+ std::vector<std::vector<std::string>> Multi1;
+ std::vector<std::vector<std::string>> Multi2;
+ std::vector<std::vector<std::string>> Multi3;
+};
+
+std::initializer_list<cm::string_view> const args = {
+ /* clang-format off */
+ "OPTION_1", // option
+ "STRING_1", // string arg missing value
+ "STRING_2", "foo", "bar", // string arg + unparsed value
+ "LIST_1", // list arg missing values
+ "LIST_2", "foo", "bar", // list arg with 2 elems
+ "LIST_3", "bar", // list arg ...
+ "LIST_3", "foo", // ... with continuation
+ "MULTI_2", // multi list with 0 lists
+ "MULTI_3", "foo", "bar", // multi list with first list with two elems
+ "MULTI_3", "bar", "foo", // multi list with second list with two elems
+ /* clang-format on */
+};
+
+bool verifyResult(Result const& result,
+ std::vector<std::string> const& unparsedArguments,
+ std::vector<std::string> const& keywordsMissingValue)
+{
+ static std::vector<std::string> const foobar = { "foo", "bar" };
+ static std::vector<std::string> const barfoo = { "bar", "foo" };
+ static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return false; \
+ } \
+ } while (false)
+
+ ASSERT_TRUE(result.Option1);
+ ASSERT_TRUE(!result.Option2);
+
+ ASSERT_TRUE(result.String1.empty());
+ ASSERT_TRUE(result.String2 == "foo");
+
+ ASSERT_TRUE(result.List1.empty());
+ ASSERT_TRUE(result.List2 == foobar);
+ ASSERT_TRUE(result.List3 == barfoo);
+
+ ASSERT_TRUE(result.Multi1.empty());
+ ASSERT_TRUE(result.Multi2.size() == 1);
+ ASSERT_TRUE(result.Multi2[0].empty());
+ ASSERT_TRUE(result.Multi3.size() == 2);
+ ASSERT_TRUE(result.Multi3[0] == foobar);
+ ASSERT_TRUE(result.Multi3[1] == barfoo);
+
+ ASSERT_TRUE(unparsedArguments.size() == 1);
+ ASSERT_TRUE(unparsedArguments[0] == "bar");
+ ASSERT_TRUE(keywordsMissingValue == missing);
+
+ return true;
+}
+
+bool testArgumentParserDynamic()
+{
+ Result result;
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+
+ cmArgumentParser<void>{}
+ .Bind("OPTION_1"_s, result.Option1)
+ .Bind("OPTION_2"_s, result.Option2)
+ .Bind("STRING_1"_s, result.String1)
+ .Bind("STRING_2"_s, result.String2)
+ .Bind("LIST_1"_s, result.List1)
+ .Bind("LIST_2"_s, result.List2)
+ .Bind("LIST_3"_s, result.List3)
+ .Bind("MULTI_1"_s, result.Multi1)
+ .Bind("MULTI_2"_s, result.Multi2)
+ .Bind("MULTI_3"_s, result.Multi3)
+ .Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+bool testArgumentParserStatic()
+{
+ static auto const parser = //
+ cmArgumentParser<Result>{}
+ .Bind("OPTION_1"_s, &Result::Option1)
+ .Bind("OPTION_2"_s, &Result::Option2)
+ .Bind("STRING_1"_s, &Result::String1)
+ .Bind("STRING_2"_s, &Result::String2)
+ .Bind("LIST_1"_s, &Result::List1)
+ .Bind("LIST_2"_s, &Result::List2)
+ .Bind("LIST_3"_s, &Result::List3)
+ .Bind("MULTI_1"_s, &Result::Multi1)
+ .Bind("MULTI_2"_s, &Result::Multi2)
+ .Bind("MULTI_3"_s, &Result::Multi3);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ Result const result =
+ parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+} // namespace
+
+int testArgumentParser(int /*unused*/, char* /*unused*/ [])
+{
+ if (!testArgumentParserDynamic()) {
+ std::cout << "While executing testArgumentParserDynamic().\n";
+ return -1;
+ }
+
+ if (!testArgumentParserStatic()) {
+ std::cout << "While executing testArgumentParserStatic().\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testRST.expect b/Tests/CMakeLib/testRST.expect
index d7b91d1b4..c19ee9400 100644
--- a/Tests/CMakeLib/testRST.expect
+++ b/Tests/CMakeLib/testRST.expect
@@ -83,6 +83,10 @@ or after a paragraph ending in two colons::
but not after a line ending in two colons::
in the middle of a paragraph.
+A literal block can be empty::
+
+
+
.. productionlist::
grammar: `production`
production: "content rendered"
diff --git a/Tests/CMakeLib/testRST.rst b/Tests/CMakeLib/testRST.rst
index 633219f8b..d2d1140f3 100644
--- a/Tests/CMakeLib/testRST.rst
+++ b/Tests/CMakeLib/testRST.rst
@@ -90,6 +90,10 @@ or after a paragraph ending in two colons::
but not after a line ending in two colons::
in the middle of a paragraph.
+A literal block can be empty::
+
+
+
.. productionlist::
grammar: `production`
production: "content rendered"
diff --git a/Tests/CMakeLib/testRange.cxx b/Tests/CMakeLib/testRange.cxx
new file mode 100644
index 000000000..b26b07b8c
--- /dev/null
+++ b/Tests/CMakeLib/testRange.cxx
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmRange.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return -1; \
+ } \
+ } while (false)
+
+int testRange(int /*unused*/, char* /*unused*/ [])
+{
+ std::vector<int> const testData = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ ASSERT_TRUE(!cmMakeRange(testData).empty());
+ ASSERT_TRUE(cmMakeRange(testData).size() == 10);
+
+ ASSERT_TRUE(!cmMakeRange(testData).advance(5).empty());
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).size() == 5);
+
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).empty());
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).size() == 0);
+
+ ASSERT_TRUE(cmMakeRange(testData).any_of([](int n) { return n % 3 == 0; }));
+ ASSERT_TRUE(cmMakeRange(testData).all_of([](int n) { return n < 11; }));
+ ASSERT_TRUE(cmMakeRange(testData).none_of([](int n) { return n > 11; }));
+
+ std::vector<int> const evenData = { 2, 4, 6, 8, 10 };
+ ASSERT_TRUE(cmMakeRange(testData).filter([](int n) { return n % 2 == 0; }) ==
+ cmMakeRange(evenData));
+
+ std::vector<std::string> const stringRange = { "1", "2", "3", "4", "5" };
+ ASSERT_TRUE(cmMakeRange(testData)
+ .transform([](int n) { return std::to_string(n); })
+ .retreat(5) == cmMakeRange(stringRange));
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx
index 96a481953..121e63985 100644
--- a/Tests/CMakeLib/testSystemTools.cxx
+++ b/Tests/CMakeLib/testSystemTools.cxx
@@ -93,5 +93,22 @@ int testSystemTools(int /*unused*/, char* /*unused*/ [])
if (!failed) {
cmPassed("cmSystemTools::strverscmp working");
}
+
+ // ----------------------------------------------------------------------
+ // Test cmSystemTools::StringToULong
+ {
+ unsigned long value;
+ cmAssert(cmSystemTools::StringToULong("1", &value) && value == 1,
+ "StringToULong parses a decimal integer.");
+ cmAssert(cmSystemTools::StringToULong(" 1", &value) && value == 1,
+ "StringToULong parses a decimal integer after whitespace.");
+ cmAssert(!cmSystemTools::StringToULong("-1", &value),
+ "StringToULong rejects a negative number.");
+ cmAssert(!cmSystemTools::StringToULong(" -1", &value),
+ "StringToULong rejects a negative number after whitespace.");
+ cmAssert(!cmSystemTools::StringToULong("1x", &value),
+ "StringToULong rejects trailing content.");
+ }
+
return failed;
}
diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx
index c99c46db5..a0bb5cd23 100644
--- a/Tests/CMakeLib/testUTF8.cxx
+++ b/Tests/CMakeLib/testUTF8.cxx
@@ -13,6 +13,21 @@ static void test_utf8_char_print(test_utf8_char const c)
static_cast<int>(d[3]));
}
+static void byte_array_print(char const* s)
+{
+ unsigned char const* d = reinterpret_cast<unsigned char const*>(s);
+ bool started = false;
+ printf("[");
+ for (; *d; ++d) {
+ if (started) {
+ printf(",");
+ }
+ started = true;
+ printf("0x%02X", static_cast<int>(*d));
+ }
+ printf("]");
+}
+
struct test_utf8_entry
{
int n;
@@ -21,17 +36,36 @@ struct test_utf8_entry
};
static test_utf8_entry const good_entry[] = {
- { 1, "\x20\x00\x00\x00", 0x0020 }, /* Space. */
- { 2, "\xC2\xA9\x00\x00", 0x00A9 }, /* Copyright. */
- { 3, "\xE2\x80\x98\x00", 0x2018 }, /* Open-single-quote. */
- { 3, "\xE2\x80\x99\x00", 0x2019 }, /* Close-single-quote. */
- { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629. */
+ { 1, "\x20\x00\x00\x00", 0x0020 }, /* Space. */
+ { 2, "\xC2\xA9\x00\x00", 0x00A9 }, /* Copyright. */
+ { 3, "\xE2\x80\x98\x00", 0x2018 }, /* Open-single-quote. */
+ { 3, "\xE2\x80\x99\x00", 0x2019 }, /* Close-single-quote. */
+ { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629. */
+ { 3, "\xED\x80\x80\x00", 0xD000 }, /* Valid 0xED prefixed codepoint. */
+ { 4, "\xF4\x8F\xBF\xBF", 0x10FFFF }, /* Highest valid RFC codepoint. */
{ 0, { 0, 0, 0, 0, 0 }, 0 }
};
static test_utf8_char const bad_chars[] = {
- "\x80\x00\x00\x00", "\xC0\x00\x00\x00", "\xE0\x00\x00\x00",
- "\xE0\x80\x80\x00", "\xF0\x80\x80\x80", { 0, 0, 0, 0, 0 }
+ "\x80\x00\x00\x00", /* Leading continuation byte. */
+ "\xC0\x80\x00\x00", /* Overlong encoding. */
+ "\xC1\x80\x00\x00", /* Overlong encoding. */
+ "\xC2\x00\x00\x00", /* Missing continuation byte. */
+ "\xE0\x00\x00\x00", /* Missing continuation bytes. */
+ "\xE0\x80\x80\x00", /* Overlong encoding. */
+ "\xF0\x80\x80\x80", /* Overlong encoding. */
+ "\xED\xA0\x80\x00", /* UTF-16 surrogate half. */
+ "\xED\xBF\xBF\x00", /* UTF-16 surrogate half. */
+ "\xF4\x90\x80\x80", /* Lowest out-of-range codepoint. */
+ "\xF5\x80\x80\x80", /* Prefix forces out-of-range codepoints. */
+ { 0, 0, 0, 0, 0 }
+};
+
+static char const* good_strings[] = { "", "ASCII", "\xC2\xA9 Kitware", 0 };
+
+static char const* bad_strings[] = {
+ "\xC0\x80", /* Modified UTF-8 for embedded 0-byte. */
+ 0
};
static void report_good(bool passed, test_utf8_char const c)
@@ -87,6 +121,46 @@ static bool decode_bad(test_utf8_char const s)
return true;
}
+static void report_valid(bool passed, char const* s)
+{
+ printf("%s: validity good ", passed ? "pass" : "FAIL");
+ byte_array_print(s);
+ printf(" (%s) ", s);
+}
+
+static void report_invalid(bool passed, char const* s)
+{
+ printf("%s: validity bad ", passed ? "pass" : "FAIL");
+ byte_array_print(s);
+ printf(" ");
+}
+
+static bool is_valid(const char* s)
+{
+ bool valid = cm_utf8_is_valid(s) != 0;
+ if (!valid) {
+ report_valid(false, s);
+ printf("expected valid, reported as invalid\n");
+ return false;
+ }
+ report_valid(true, s);
+ printf("valid as expected\n");
+ return true;
+}
+
+static bool is_invalid(const char* s)
+{
+ bool valid = cm_utf8_is_valid(s) != 0;
+ if (valid) {
+ report_invalid(false, s);
+ printf("expected invalid, reported as valid\n");
+ return false;
+ }
+ report_invalid(true, s);
+ printf("invalid as expected\n");
+ return true;
+}
+
int testUTF8(int /*unused*/, char* /*unused*/ [])
{
int result = 0;
@@ -94,11 +168,27 @@ int testUTF8(int /*unused*/, char* /*unused*/ [])
if (!decode_good(*e)) {
result = 1;
}
+ if (!is_valid(e->str)) {
+ result = 1;
+ }
}
for (test_utf8_char const* c = bad_chars; (*c)[0]; ++c) {
if (!decode_bad(*c)) {
result = 1;
}
+ if (!is_invalid(*c)) {
+ result = 1;
+ }
+ }
+ for (char const** s = good_strings; *s; ++s) {
+ if (!is_valid(*s)) {
+ result = 1;
+ }
+ }
+ for (char const** s = bad_strings; *s; ++s) {
+ if (!is_invalid(*s)) {
+ result = 1;
+ }
}
return result;
}
diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx
new file mode 100644
index 000000000..72ae60203
--- /dev/null
+++ b/Tests/CMakeLib/testUVProcessChain.cxx
@@ -0,0 +1,335 @@
+#include "cmUVProcessChain.h"
+
+#include "cmAlgorithms.h"
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <csignal>
+
+struct ExpectedStatus
+{
+ bool Finished;
+ bool MatchExitStatus;
+ bool MatchTermSignal;
+ cmUVProcessChain::Status Status;
+};
+
+static const std::vector<ExpectedStatus> status1 = {
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+};
+
+static const std::vector<ExpectedStatus> status2 = {
+ { true, true, true, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+};
+
+static const std::vector<ExpectedStatus> status3 = {
+ { true, true, true, { 0, 0 } },
+ { true, true, true, { 1, 0 } },
+#ifdef _WIN32
+ { true, true, true, { 2, 0 } },
+#else
+ { true, false, true, { 0, SIGABRT } },
+#endif
+};
+
+bool operator==(const cmUVProcessChain::Status* actual,
+ const ExpectedStatus& expected)
+{
+ if (!expected.Finished) {
+ return !actual;
+ } else if (!actual) {
+ return false;
+ }
+ if (expected.MatchExitStatus &&
+ expected.Status.ExitStatus != actual->ExitStatus) {
+ return false;
+ }
+ if (expected.MatchTermSignal &&
+ expected.Status.TermSignal != actual->TermSignal) {
+ return false;
+ }
+ return true;
+}
+
+bool resultsMatch(const std::vector<const cmUVProcessChain::Status*>& actual,
+ const std::vector<ExpectedStatus>& expected)
+{
+ return actual.size() == expected.size() &&
+ std::equal(actual.begin(), actual.end(), expected.begin());
+}
+
+std::string getInput(std::istream& input)
+{
+ char buffer[1024];
+ std::ostringstream str;
+ do {
+ input.read(buffer, 1024);
+ str.write(buffer, input.gcount());
+ } while (input.gcount() > 0);
+ return str.str();
+}
+
+template <typename T>
+std::function<std::ostream&(std::ostream&)> printExpected(bool match,
+ const T& value)
+{
+ return [match, value](std::ostream& stream) -> std::ostream& {
+ if (match) {
+ stream << value;
+ } else {
+ stream << "*";
+ }
+ return stream;
+ };
+}
+
+std::ostream& operator<<(
+ std::ostream& stream,
+ const std::function<std::ostream&(std::ostream&)>& func)
+{
+ return func(stream);
+}
+
+void printResults(const std::vector<const cmUVProcessChain::Status*>& actual,
+ const std::vector<ExpectedStatus>& expected)
+{
+ std::cout << "Expected: " << std::endl;
+ for (auto const& e : expected) {
+ if (e.Finished) {
+ std::cout << " ExitStatus: "
+ << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
+ << ", TermSignal: "
+ << printExpected(e.MatchTermSignal, e.Status.TermSignal)
+ << std::endl;
+ } else {
+ std::cout << " null" << std::endl;
+ }
+ }
+ std::cout << "Actual:" << std::endl;
+ for (auto const& a : actual) {
+ if (a) {
+ std::cout << " ExitStatus: " << a->ExitStatus
+ << ", TermSignal: " << a->TermSignal << std::endl;
+ } else {
+ std::cout << " null" << std::endl;
+ }
+ }
+}
+
+bool checkExecution(cmUVProcessChainBuilder& builder,
+ std::unique_ptr<cmUVProcessChain>& chain)
+{
+ std::vector<const cmUVProcessChain::Status*> status;
+
+ chain = cm::make_unique<cmUVProcessChain>(builder.Start());
+ if (!chain->Valid()) {
+ std::cout << "Valid() returned false, should be true" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status1)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status1);
+ return false;
+ }
+
+ if (chain->Wait(6000)) {
+ std::cout << "Wait() returned true, should be false" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status2)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status2);
+ return false;
+ }
+
+ if (!chain->Wait()) {
+ std::cout << "Wait() returned false, should be true" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status3)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status3);
+ return false;
+ }
+
+ return true;
+}
+
+bool checkOutput(std::istream& outputStream, std::istream& errorStream)
+{
+ std::string output = getInput(outputStream);
+ if (output != "HELO WRD!") {
+ std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
+ << std::endl;
+ return false;
+ }
+
+ std::string error = getInput(errorStream);
+ if (error.length() != 3 || error.find('1') == std::string::npos ||
+ error.find('2') == std::string::npos ||
+ error.find('3') == std::string::npos) {
+ std::cout << "Error was \"" << error << "\", expected \"123\""
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainBuiltin(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" })
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (!chain->OutputStream()) {
+ std::cout << "OutputStream() was null, expecting not null" << std::endl;
+ return false;
+ }
+ if (!chain->ErrorStream()) {
+ std::cout << "ErrorStream() was null, expecting not null" << std::endl;
+ return false;
+ }
+
+ if (!checkOutput(*chain->OutputStream(), *chain->ErrorStream())) {
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainExternal(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ int outputPipe[2], errorPipe[2];
+ cm::uv_pipe_ptr outputInPipe, outputOutPipe, errorInPipe, errorOutPipe;
+
+ if (cmGetPipes(outputPipe) < 0) {
+ std::cout << "Error creating pipes" << std::endl;
+ return false;
+ }
+ if (cmGetPipes(errorPipe) < 0) {
+ std::cout << "Error creating pipes" << std::endl;
+ return false;
+ }
+
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" })
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, outputPipe[1])
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, errorPipe[1]);
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (chain->OutputStream()) {
+ std::cout << "OutputStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+ if (chain->ErrorStream()) {
+ std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+
+ outputOutPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(outputOutPipe, outputPipe[1]);
+ outputOutPipe.reset();
+
+ errorOutPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(errorOutPipe, errorPipe[1]);
+ errorOutPipe.reset();
+
+ outputInPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(outputInPipe, outputPipe[0]);
+ cmUVStreambuf outputBuf;
+ outputBuf.open(outputInPipe);
+ std::istream outputStream(&outputBuf);
+
+ errorInPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(errorInPipe, errorPipe[0]);
+ cmUVStreambuf errorBuf;
+ errorBuf.open(errorInPipe);
+ std::istream errorStream(&errorBuf);
+
+ if (!checkOutput(outputStream, errorStream)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainNone(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" });
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (chain->OutputStream()) {
+ std::cout << "OutputStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+ if (chain->ErrorStream()) {
+ std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+int testUVProcessChain(int argc, char** const argv)
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainBuiltin(argv[1])) {
+ std::cout << "While executing testUVProcessChainBuiltin().\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainExternal(argv[1])) {
+ std::cout << "While executing testUVProcessChainExternal().\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainNone(argv[1])) {
+ std::cout << "While executing testUVProcessChainNone().\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
new file mode 100644
index 000000000..263665d59
--- /dev/null
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -0,0 +1,72 @@
+#include <chrono>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <string>
+#include <thread>
+
+#include <cctype>
+#include <cstdlib>
+
+std::string getStdin()
+{
+ char buffer[1024];
+ std::ostringstream str;
+ do {
+ std::cin.read(buffer, 1024);
+ str.write(buffer, std::cin.gcount());
+ } while (std::cin.gcount() > 0);
+ return str.str();
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ return -1;
+ }
+
+ std::string command = argv[1];
+ if (command == "echo") {
+ std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+ std::cout << "HELLO world!" << std::flush;
+ std::cerr << "1" << std::flush;
+ return 0;
+ }
+ if (command == "capitalize") {
+ std::this_thread::sleep_for(std::chrono::milliseconds(9000));
+ std::string input = getStdin();
+ for (auto& c : input) {
+ c = static_cast<char>(std::toupper(c));
+ }
+ std::cout << input << std::flush;
+ std::cerr << "2" << std::flush;
+ return 1;
+ }
+ if (command == "dedup") {
+ // Use a nested scope to free all resources before aborting below.
+ {
+ std::string input = getStdin();
+ std::set<char> seen;
+ std::string output;
+ for (auto c : input) {
+ if (!seen.count(c)) {
+ seen.insert(c);
+ output += c;
+ }
+ }
+ std::cout << output << std::flush;
+ std::cerr << "3" << std::flush;
+ }
+
+ // On Windows, the exit code of abort() is different between debug and
+ // release builds, and does not yield a term_signal in libuv in either
+ // case. For the sake of simplicity, we just return another non-zero code.
+#ifdef _WIN32
+ return 2;
+#else
+ std::abort();
+#endif
+ }
+
+ return -1;
+}
diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx
index 1c1da76a8..2aeaf2c02 100644
--- a/Tests/CMakeLib/testUVRAII.cxx
+++ b/Tests/CMakeLib/testUVRAII.cxx
@@ -171,11 +171,59 @@ static bool testAllMoves()
return true;
};
+static bool testLoopReset()
+{
+ bool closed = false;
+ cm::uv_loop_ptr loop;
+ loop.init();
+
+ uv_timer_t timer;
+ uv_timer_init(loop, &timer);
+ timer.data = &closed;
+ uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) {
+ auto closedPtr = static_cast<bool*>(handle->data);
+ *closedPtr = true;
+ });
+
+ loop.reset();
+ if (!closed) {
+ std::cerr << "uv_loop_ptr did not finish" << std::endl;
+ return false;
+ }
+
+ return true;
+};
+
+static bool testLoopDestructor()
+{
+ bool closed = false;
+
+ uv_timer_t timer;
+ {
+ cm::uv_loop_ptr loop;
+ loop.init();
+
+ uv_timer_init(loop, &timer);
+ timer.data = &closed;
+ uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) {
+ auto closedPtr = static_cast<bool*>(handle->data);
+ *closedPtr = true;
+ });
+ }
+
+ if (!closed) {
+ std::cerr << "uv_loop_ptr did not finish" << std::endl;
+ return false;
+ }
+
+ return true;
+};
+
int testUVRAII(int, char** const)
{
if ((testAsyncShutdown() &&
testAsyncDtor() & testAsyncMove() & testCrossAssignment() &
- testAllMoves()) == 0) {
+ testAllMoves() & testLoopReset() & testLoopDestructor()) == 0) {
return -1;
}
return 0;
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
new file mode 100644
index 000000000..39655f372
--- /dev/null
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -0,0 +1,457 @@
+#include "cmUVStreambuf.h"
+
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+
+#include "cm_uv.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cstring>
+
+#include <stdint.h>
+
+#define TEST_STR_LINE_1 "This string must be exactly 128 characters long so"
+#define TEST_STR_LINE_2 "that we can test CMake's std::streambuf integration"
+#define TEST_STR_LINE_3 "with libuv's uv_stream_t."
+#define TEST_STR TEST_STR_LINE_1 "\n" TEST_STR_LINE_2 "\n" TEST_STR_LINE_3
+
+bool writeDataToStreamPipe(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe,
+ char* outputData, unsigned int outputDataLength,
+ const char* /* unused */)
+{
+ int err;
+
+ // Create the pipe
+ int pipeHandles[2];
+ if (cmGetPipes(pipeHandles) < 0) {
+ std::cout << "Could not open pipe" << std::endl;
+ return false;
+ }
+
+ cm::uv_pipe_ptr outputPipe;
+ inputPipe.init(loop, 0);
+ outputPipe.init(loop, 0);
+ uv_pipe_open(inputPipe, pipeHandles[0]);
+ uv_pipe_open(outputPipe, pipeHandles[1]);
+
+ // Write data for reading
+ uv_write_t writeReq;
+ struct WriteCallbackData
+ {
+ bool Finished = false;
+ int Status;
+ } writeData;
+ writeReq.data = &writeData;
+ uv_buf_t outputBuf;
+ outputBuf.base = outputData;
+ outputBuf.len = outputDataLength;
+ if ((err = uv_write(&writeReq, outputPipe, &outputBuf, 1,
+ [](uv_write_t* req, int status) {
+ auto data = static_cast<WriteCallbackData*>(req->data);
+ data->Finished = true;
+ data->Status = status;
+ })) < 0) {
+ std::cout << "Could not write to pipe: " << uv_strerror(err) << std::endl;
+ return false;
+ }
+ while (!writeData.Finished) {
+ uv_run(&loop, UV_RUN_ONCE);
+ }
+ if (writeData.Status < 0) {
+ std::cout << "Status is " << uv_strerror(writeData.Status)
+ << ", should be 0" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool writeDataToStreamProcess(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe,
+ char* outputData, unsigned int /* unused */,
+ const char* cmakeCommand)
+{
+ int err;
+
+ inputPipe.init(loop, 0);
+ std::vector<std::string> arguments = { cmakeCommand, "-E", "echo_append",
+ outputData };
+ std::vector<const char*> processArgs;
+ for (auto const& arg : arguments) {
+ processArgs.push_back(arg.c_str());
+ }
+ processArgs.push_back(nullptr);
+ std::vector<uv_stdio_container_t> stdio(3);
+ stdio[0].flags = UV_IGNORE;
+ stdio[0].data.stream = nullptr;
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = inputPipe;
+ stdio[2].flags = UV_IGNORE;
+ stdio[2].data.stream = nullptr;
+
+ struct ProcessExitData
+ {
+ bool Finished = false;
+ int64_t ExitStatus;
+ int TermSignal;
+ } exitData;
+ cm::uv_process_ptr process;
+ auto options = uv_process_options_t();
+ options.file = cmakeCommand;
+ options.args = const_cast<char**>(processArgs.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+ options.stdio = stdio.data();
+ options.stdio_count = static_cast<int>(stdio.size());
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto data = static_cast<ProcessExitData*>(handle->data);
+ data->Finished = true;
+ data->ExitStatus = exitStatus;
+ data->TermSignal = termSignal;
+ };
+ if ((err = process.spawn(loop, options, &exitData)) < 0) {
+ std::cout << "Could not spawn process: " << uv_strerror(err) << std::endl;
+ return false;
+ }
+ while (!exitData.Finished) {
+ uv_run(&loop, UV_RUN_ONCE);
+ }
+ if (exitData.ExitStatus != 0) {
+ std::cout << "Process exit status is " << exitData.ExitStatus
+ << ", should be 0" << std::endl;
+ return false;
+ }
+ if (exitData.TermSignal != 0) {
+ std::cout << "Process term signal is " << exitData.TermSignal
+ << ", should be 0" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVStreambufRead(
+ bool (*cb)(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, char* outputData,
+ unsigned int outputDataLength, const char* cmakeCommand),
+ const char* cmakeCommand)
+{
+ char outputData[] = TEST_STR;
+ bool success = false;
+ cm::uv_loop_ptr loop;
+ loop.init();
+ cm::uv_pipe_ptr inputPipe;
+ std::vector<char> inputData(128);
+ std::streamsize readLen;
+ std::string line;
+ cm::uv_timer_ptr timer;
+
+ // Create the streambuf
+ cmUVStreambuf inputBuf(64);
+ std::istream inputStream(&inputBuf);
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform first read test - read all the data
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if (std::memcmp(inputData.data(), outputData, 128)) {
+ std::cout << "Read data does not match write data" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ inputData.assign(128, char{});
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform second read test - read some data and then close
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 64)) != 64) {
+ std::cout << "sgetn() returned " << readLen << ", should be 64"
+ << std::endl;
+ goto end;
+ }
+ if (std::memcmp(inputData.data(), outputData, 64)) {
+ std::cout << "Read data does not match write data" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 8) {
+ std::cout << "in_avail() returned " << readLen << ", should be 8"
+ << std::endl;
+ goto end;
+ }
+ inputData.assign(128, char{});
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform third read test - read line by line
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_1) {
+ std::cout << "Line 1 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_1 "\"" << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_2) {
+ std::cout << "Line 2 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_2 "\"" << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_3) {
+ std::cout << "Line 3 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_3 "\"" << std::endl;
+ goto end;
+ }
+
+ if (std::getline(inputStream, line)) {
+ std::cout << "getline returned true, should be false" << std::endl;
+ goto end;
+ }
+
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform fourth read test - run the event loop outside of underflow()
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ uv_run(loop, UV_RUN_DEFAULT);
+ if ((readLen = inputBuf.in_avail()) != 72) {
+ std::cout << "in_avail() returned " << readLen << ", should be 72"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform fifth read test - close the streambuf in the middle of a read
+ timer.init(*loop, &inputBuf);
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ uv_timer_start(timer,
+ [](uv_timer_t* handle) {
+ auto buf = static_cast<cmUVStreambuf*>(handle->data);
+ buf->close();
+ },
+ 0, 0);
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ success = true;
+
+end:
+ return success;
+}
+
+int testUVStreambuf(int argc, char** const argv)
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ if (!testUVStreambufRead(writeDataToStreamPipe, argv[1])) {
+ std::cout << "While executing testUVStreambufRead() with pipe.\n";
+ return -1;
+ }
+
+ if (!testUVStreambufRead(writeDataToStreamProcess, argv[1])) {
+ std::cout << "While executing testUVStreambufRead() with process.\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 588c8e0d2..e73b277f1 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -22,6 +22,7 @@ macro(ADD_TEST_MACRO NAME)
endmacro()
include(${CMAKE_CURRENT_SOURCE_DIR}/CheckFortran.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CheckSwift.cmake)
# Fake a user home directory to avoid polluting the real one.
if(DEFINED ENV{HOME} AND NOT CTEST_NO_TEST_HOME)
@@ -365,11 +366,16 @@ if(BUILD_TESTING)
((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
(NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
if(CMAKE_GENERATOR STREQUAL "Xcode")
- ADD_TEST_MACRO(SwiftMix SwiftMix)
- ADD_TEST_MACRO(SwiftOnly SwiftOnly)
+ set(CMake_TEST_XCODE_SWIFT 1)
endif()
endif()
endif()
+ if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+ ADD_TEST_MACRO(SwiftOnly SwiftOnly)
+ if(CMake_TEST_XCODE_SWIFT)
+ ADD_TEST_MACRO(SwiftMix SwiftMix)
+ endif()
+ endif()
if(CMAKE_Fortran_COMPILER)
ADD_TEST_MACRO(FortranOnly FortranOnly)
endif()
@@ -459,7 +465,7 @@ if(BUILD_TESTING)
set(runCxxDialectTest 1)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
- AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
+ AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4 AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
if(NOT APPLE OR POLICY CMP0025)
set(runCxxDialectTest 1)
endif()
@@ -764,14 +770,14 @@ if(BUILD_TESTING)
file(WRITE "${_TEST_DIR}/nightly-cmake.sh"
"cd ${_TEST_DIR}
${CMake_BINARY_DIR}/bin/cmake -DCMAKE_CREATE_VERSION=nightly -P ${CMake_SOURCE_DIR}/Utilities/Release/${script}
-${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release/upload_release.cmake
+${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGHTLY_RELEASES}'
")
add_test(${name} /bin/sh ${_TEST_DIR}/nightly-cmake.sh)
if(COMMAND SET_TESTS_PROPERTIES AND COMMAND GET_TEST_PROPERTY)
set_tests_properties (${name} PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
endif()
endmacro()
- if(CMAKE_BUILD_NIGHTLY_RELEASES)
+ if(CMake_BUILD_NIGHTLY_RELEASES)
ADD_NIGHTLY_BUILD_TEST(CMakeNightlyWin32
win32_release.cmake)
ADD_NIGHTLY_BUILD_TEST(CMakeNightlyWin64
@@ -1413,10 +1419,18 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_subdirectory(FindCURL)
endif()
+ if(CMake_TEST_FindCups)
+ add_subdirectory(FindCups)
+ endif()
+
if(CMake_TEST_FindDoxygen)
add_subdirectory(FindDoxygen)
endif()
+ if(CMake_TEST_FindEnvModules)
+ add_subdirectory(FindEnvModules)
+ endif()
+
if(CMake_TEST_FindEXPAT)
add_subdirectory(FindEXPAT)
endif()
@@ -1441,6 +1455,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_subdirectory(FindGit)
endif()
+ if(CMake_TEST_FindGLEW)
+ add_subdirectory(FindGLEW)
+ endif()
+
if(CMake_TEST_FindGSL)
add_subdirectory(FindGSL)
endif()
@@ -1450,6 +1468,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_subdirectory(GoogleTest)
endif()
+ if(CMake_TEST_FindGTK2)
+ add_subdirectory(FindGTK2)
+ endif()
+
if(CMake_TEST_FindIconv)
add_subdirectory(FindIconv)
endif()
@@ -1593,11 +1615,6 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(FindMatlab.r2018a_check ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
endif()
- find_package(GTK2 QUIET)
- if(GTK2_FOUND)
- add_subdirectory(FindGTK2)
- endif()
-
add_test(ExternalProject ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/ExternalProject"
@@ -1984,6 +2001,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
ADD_TEST_MACRO(PrecompiledHeader foo)
endif()
+ set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+ ADD_TEST_MACRO(MSVCRuntimeLibrary)
+ if(CMAKE_Fortran_COMPILER)
+ ADD_TEST_MACRO(MSVCRuntimeLibrary.Fortran)
+ endif()
endif()
if(MSVC OR
"${CMAKE_GENERATOR}" MATCHES "(MSYS|MinGW) Makefiles")
@@ -1992,7 +2014,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CheckCompilerRelatedVariables CheckCompilerRelatedVariables)
- if("${CMAKE_GENERATOR}" MATCHES "Makefile")
+ if("${CMAKE_GENERATOR}" MATCHES "Makefile" OR
+ "${CMAKE_GENERATOR}" MATCHES "Ninja")
add_test(MakeClean ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/MakeClean"
@@ -2313,6 +2336,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
--build-generator "Green Hills MULTI"
--build-project test
--build-config $<CONFIGURATION>
+ --force-new-ctest-process
--build-options ${ghs_target_arch} ${ghs_toolset_name} ${ghs_toolset_root} ${ghs_target_platform}
${ghs_os_root} ${ghs_os_dir} ${ghs_bsp_name} ${_ghs_build_opts} ${_ghs_toolset_extra}
${_ghs_test_command}
@@ -2324,7 +2348,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
endmacro()
macro(add_test_GhsMulti_rename_install test_name)
add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
- "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} -P ./cmake_install.cmake)
+ "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target install)
endmacro()
#unset ghs config variables
unset(ghs_config_name)
@@ -2379,6 +2403,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_test_GhsMulti(compiler_options_kernel GhsMultiCompilerOptions Kernel "-DRUN_TEST=KERNEL_FLAGS -DRUN_TEST_BUILD_TYPE=DEBUG")
add_test_GhsMulti(try_compile_copy GhsMultiCopyFile "" "")
add_test_GhsMulti(ghs_platform GhsMultiPlatform "" "")
+ add_test_GhsMulti(custom_target GhsMultiCustomTarget "" "")
+ add_test_GhsMulti(dep_order GhsMultiDepOrder "" "")
+ add_test_GhsMulti(external_project GhsMultiExternalProject "" "")
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}")
#unset ghs config variables
unset(ghs_config_name)
@@ -2505,24 +2532,17 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
FAIL_REGULAR_EXPRESSION "CMakeLists.txt:5 \\(set\\):")
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedUnusedViaUnset")
- if("${CMAKE_GENERATOR}" MATCHES "Makefile" AND NOT WIN32)
- # Ninja does not support ADDITIONAL_MAKE_CLEAN_FILES and therefore fails
- # this test. (See #13371)
- # Apparently Visual Studio does not support it either. As the MakeClean
- # test above is only run with the Makefiles generator, only run this
- # test with the Makefiles generator also.
- add_test(WarnUnusedCliUnused ${CMAKE_CTEST_COMMAND}
- --build-and-test
- "${CMake_SOURCE_DIR}/Tests/WarnUnusedCliUnused"
- "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused"
- ${build_generator_args}
- --build-project WarnUnusedCliUnused
- --build-options ${build_options}
- "-DUNUSED_CLI_VARIABLE=Unused")
- set_tests_properties(WarnUnusedCliUnused PROPERTIES
- PASS_REGULAR_EXPRESSION "CMake Warning:.*Manually-specified variables were not used by the project:.* UNUSED_CLI_VARIABLE")
- list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused")
- endif()
+ add_test(WarnUnusedCliUnused ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/WarnUnusedCliUnused"
+ "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused"
+ ${build_generator_args}
+ --build-project WarnUnusedCliUnused
+ --build-options ${build_options}
+ "-DUNUSED_CLI_VARIABLE=Unused")
+ set_tests_properties(WarnUnusedCliUnused PROPERTIES
+ PASS_REGULAR_EXPRESSION "CMake Warning:.*Manually-specified variables were not used by the project:.* UNUSED_CLI_VARIABLE")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused")
add_test(WarnUnusedCliUsed ${CMAKE_CTEST_COMMAND}
--build-and-test
@@ -3264,12 +3284,14 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
--output-log "${CMake_BINARY_DIR}/Tests/CTestTest/testOutput.log"
)
- configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest2/test.cmake.in"
- "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" @ONLY ESCAPE_QUOTES)
- add_test(CTestTest2 ${CMAKE_CTEST_COMMAND}
- -S "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" -V
- --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
- )
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest2/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" @ONLY ESCAPE_QUOTES)
+ add_test(CTestTest2 ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
+ )
+ endif()
if("${CMAKE_GENERATOR}" MATCHES "Makefiles" OR "${CMAKE_GENERATOR}" MATCHES "Ninja")
configure_file("${CMake_SOURCE_DIR}/Tests/CTestTestLaunchers/test.cmake.in"
@@ -3301,11 +3323,13 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
endif ()
- get_test_property(CTestTest2 TIMEOUT PREVIOUS_TIMEOUT)
- if ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
- set_tests_properties ( CTestTest2
- PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
- endif ()
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ get_test_property(CTestTest2 TIMEOUT PREVIOUS_TIMEOUT)
+ if("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
+ set_tests_properties ( CTestTest2
+ PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+ endif()
+ endif()
endif ()
if(CMake_TEST_EXTERNAL_CMAKE)
@@ -3369,6 +3393,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
--build-options ${build_options}
-DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
-DCMake_TEST_Fortran_SUBMODULES:BOOL=${CMake_TEST_Fortran_SUBMODULES}
+ ${CMake_TEST_FortranModules_BUILD_OPTIONS}
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/FortranModules")
endif()
diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt
index f40524faa..1aeab8b39 100644
--- a/Tests/CMakeOnly/CMakeLists.txt
+++ b/Tests/CMakeOnly/CMakeLists.txt
@@ -56,6 +56,18 @@ add_test(CMakeOnly.ProjectInclude ${CMAKE_CMAKE_COMMAND}
-P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
)
+add_test(CMakeOnly.ProjectIncludeAny ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectIncludeAny
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectInclude/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+add_test(CMakeOnly.ProjectIncludeBefore ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectIncludeBefore
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
include(CMakeParseArguments)
function(add_major_test module)
diff --git a/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
index 9be69f128..1f9d3acb7 100644
--- a/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
@@ -57,7 +57,7 @@ else()
message("Unhandled Platform")
endif()
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
check_cxx_compiler_flag("-x c++" HAVE_X_CXX)
if(NOT HAVE_X_CXX)
message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} compiler flag '-x c++' check failed")
diff --git a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
index f5336dc03..ca4becb77 100644
--- a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
@@ -7,7 +7,8 @@ set(expect_C 1)
set(expect_CXX 1)
unset(expect_Fortran)
set(expect_NoSuchLanguage 0)
-foreach(lang C CXX Fortran NoSuchLanguage)
+
+foreach(lang C CXX Fortran CUDA NoSuchLanguage)
check_language(${lang})
if(NOT DEFINED CMAKE_${lang}_COMPILER)
message(FATAL_ERROR "check_language(${lang}) did not set result")
diff --git a/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
index a9abb4ad7..ffce488f4 100644
--- a/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
+++ b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
@@ -1,4 +1,4 @@
-project(ProjectInclude)
+project(ProjectInclude LANGUAGES NONE)
if(NOT AUTO_INCLUDE)
message(FATAL_ERROR "include file not found")
endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
new file mode 100644
index 000000000..ffce488f4
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
new file mode 100644
index 000000000..5cd9cba2c
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(FOO TRUE)
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
new file mode 100644
index 000000000..0a4799df3
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
@@ -0,0 +1,9 @@
+if(NOT FOO)
+ message(FATAL_ERROR "FOO is not set")
+endif()
+
+if(NOT "${PROJECT_NAME}" STREQUAL "")
+ message(FATAL_ERROR "PROJECT_NAME should be empty")
+endif()
+
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/COnly/CMakeLists.txt b/Tests/COnly/CMakeLists.txt
index b3cc43813..3037f13cb 100644
--- a/Tests/COnly/CMakeLists.txt
+++ b/Tests/COnly/CMakeLists.txt
@@ -7,7 +7,7 @@ add_library(testc1 STATIC libc1.c)
add_library(testc2 SHARED libc2.c)
add_executable (COnly conly.c foo.c foo.h)
target_link_libraries(COnly testc1 testc2)
-if(MSVC_VERSION)
+if(MSVC_VERSION AND NOT CMAKE_C_COMPILER_ID STREQUAL Clang OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set_target_properties(COnly PROPERTIES
LINK_FLAGS " /NODEFAULTLIB:\"libcdg.lib\" /NODEFAULTLIB:\"libcmtg.lib\" /NODEFAULTLIB:\"foomsvcrt.lib\" /NODEFAULTLIB:\"libbar.lib\" /NODEFAULTLIB:\"libfooba.lib\"")
endif()
diff --git a/Tests/CTestCoverageCollectGCOV/fakegcov.cmake b/Tests/CTestCoverageCollectGCOV/fakegcov.cmake
index b0c3a9b9f..6df429256 100644
--- a/Tests/CTestCoverageCollectGCOV/fakegcov.cmake
+++ b/Tests/CTestCoverageCollectGCOV/fakegcov.cmake
@@ -1,14 +1,17 @@
+function(create_gcov_file gcda_full_path)
+ get_filename_component(gcda_name ${gcda_full_path} NAME)
+ string(REPLACE ".gcda" ".gcov" gcov_name "${gcda_name}")
+
+ file(STRINGS "${gcda_full_path}" source_file LIMIT_COUNT 1 ENCODING UTF-8)
+
+ file(WRITE "${CMAKE_SOURCE_DIR}/${gcov_name}"
+ " -: 0:Source:${source_file}"
+ )
+endfunction()
+
foreach(I RANGE 0 ${CMAKE_ARGC})
if("${CMAKE_ARGV${I}}" MATCHES ".*\\.gcda")
set(gcda_file "${CMAKE_ARGV${I}}")
+ create_gcov_file(${gcda_file})
endif()
endforeach()
-
-get_filename_component(gcda_name ${gcda_file} NAME)
-string(REPLACE ".gcda" ".gcov" gcov_name "${gcda_name}")
-
-file(STRINGS "${gcda_file}" source_file LIMIT_COUNT 1 ENCODING UTF-8)
-
-file(WRITE "${CMAKE_SOURCE_DIR}/${gcov_name}"
- " -: 0:Source:${source_file}"
-)
diff --git a/Tests/CheckSwift.cmake b/Tests/CheckSwift.cmake
new file mode 100644
index 000000000..fcbae7ef9
--- /dev/null
+++ b/Tests/CheckSwift.cmake
@@ -0,0 +1,61 @@
+if(NOT CMAKE_GENERATOR MATCHES "Xcode|Ninja")
+ set(CMAKE_Swift_COMPILER "")
+ return()
+endif()
+
+if(NOT DEFINED CMAKE_Swift_COMPILER)
+ set(_desc "Looking for a Swift compiler")
+ message(STATUS ${_desc})
+
+ file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift)
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift/CMakeLists.txt"
+ "cmake_minimum_required(VERSION 3.14)
+project(CheckSwift Swift)
+file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
+ \"set(CMAKE_Swift_COMPILER \\\"\${CMAKE_Swift_COMPILER}\\\")\\n\"
+ \"set(CMAKE_Swift_FLAGS \\\"\${CMAKE_Swift_FLAGS}\\\")\\n\")
+")
+
+ if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
+ else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+ endif()
+
+ execute_process(WORKING_DIRECTORY
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift
+ COMMAND
+ ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ TIMEOUT
+ 60
+ OUTPUT_VARIABLE
+ output
+ ERROR_VARIABLE
+ output
+ RESULT_VARIABLE
+ result)
+
+ include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift/result.cmake
+ OPTIONAL)
+ if(CMAKE_Swift_COMPILER AND "${result}" STREQUAL "0")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${_desc} passed with the following output:\n"
+ "${output}\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${_desc} failed with the following output:\n"
+ "${output}\n")
+ endif()
+
+ message(STATUS "${_desc} - ${CMAKE_Swift_COMPILER}")
+
+ set(CMAKE_Swift_COMPILER "${CMAKE_Swift_COMPILER}" CACHE FILEPATH "Swift compiler")
+ set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS}" CACHE STRING "Swift flags")
+
+ mark_as_advanced(CMAKE_Swift_COMPILER)
+ mark_as_advanced(CMAKE_Swift_FLAGS)
+endif()
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index b0bc6567d..060fb4940 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -15,17 +15,21 @@ macro(run_test feature lang)
endif()
endmacro()
-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})
- run_test(${feature} C)
-endforeach()
+if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+ 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})
+ run_test(${feature} C)
+ endforeach()
+endif()
-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})
- run_test(${feature} CXX)
-endforeach()
+if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+ 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})
+ run_test(${feature} CXX)
+ endforeach()
+endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
@@ -48,6 +52,16 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.15)
+ # SunPro 5.14 accepts -std=c++14 and compiles two features but does
+ # not define __cplusplus to a value different than with -std=c++11.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_aggregate_default_initializers
+ cxx_digit_separators
+ )
+ endif()
+
+ # FIXME: Do any of these work correctly on SunPro 5.13 or above?
list(REMOVE_ITEM CXX_non_features
cxx_attribute_deprecated
cxx_contextual_conversions
@@ -338,11 +352,11 @@ else()
add_executable(CompileFeaturesGenex2 genex_test.cpp)
target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
- target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs})
+ target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
add_library(std_11_iface INTERFACE)
target_compile_features(std_11_iface INTERFACE cxx_std_11)
add_executable(CompileFeaturesGenex3 genex_test.cpp)
target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
- target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs})
+ target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
endif()
diff --git a/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp
index 7b3602cd5..953148d75 100644
--- a/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp
+++ b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp
@@ -22,6 +22,7 @@ constexpr int g(const int (&is)[4])
int someFunc()
{
- constexpr int k3 = g({ 4, 5, 6, 7 });
+ constexpr int values[4] = { 4, 5, 6, 7 };
+ constexpr int k3 = g(values);
return k3 - 42;
}
diff --git a/Tests/CompileFeatures/genex_test.cpp b/Tests/CompileFeatures/genex_test.cpp
index 59f9006e6..53dce625a 100644
--- a/Tests/CompileFeatures/genex_test.cpp
+++ b/Tests/CompileFeatures/genex_test.cpp
@@ -15,10 +15,10 @@
# if !HAVE_CXX_STD_11
# error HAVE_CXX_STD_11 is false with CXX_STANDARD == 11
# endif
-# if HAVE_CXX_STD_14
+# if HAVE_CXX_STD_14 && !defined(ALLOW_LATER_STANDARDS)
# error HAVE_CXX_STD_14 is true with CXX_STANDARD == 11
# endif
-# if HAVE_CXX_STD_17
+# if HAVE_CXX_STD_17 && !defined(ALLOW_LATER_STANDARDS)
# error HAVE_CXX_STD_17 is true with CXX_STANDARD == 11
# endif
#endif
@@ -31,17 +31,6 @@
# if !EXPECT_OVERRIDE_CONTROL
# error "Expect no override control feature"
# endif
-
-struct A
-{
- virtual int getA() { return 7; }
-};
-
-struct B final : A
-{
- int getA() override { return 42; }
-};
-
#endif
#if !HAVE_AUTO_TYPE
diff --git a/Tests/CompileOptions/CMakeLists.txt b/Tests/CompileOptions/CMakeLists.txt
index 15a993c68..1433462ba 100644
--- a/Tests/CompileOptions/CMakeLists.txt
+++ b/Tests/CompileOptions/CMakeLists.txt
@@ -25,6 +25,7 @@ set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS
"-DTEST_DEFINE"
"-DNEEDS_ESCAPE=\"E$CAPE\""
"$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE_GNU>"
+ "$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-DTEST_DEFINE_CXX_AND_GNU>"
"SHELL:" # produces no options
${c_tests}
${cxx_tests}
@@ -42,7 +43,7 @@ else()
)
endif()
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Borland|Embarcadero")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Borland|Embarcadero" AND NOT "${CMAKE_GENERATOR}" MATCHES "NMake Makefiles")
set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS
"-DTEST_OCTOTHORPE=\"#\""
)
diff --git a/Tests/CompileOptions/main.cpp b/Tests/CompileOptions/main.cpp
index d94a169c7..ebc101762 100644
--- a/Tests/CompileOptions/main.cpp
+++ b/Tests/CompileOptions/main.cpp
@@ -10,6 +10,9 @@
# ifndef TEST_DEFINE_GNU
# error Expected definition TEST_DEFINE_GNU
# endif
+# ifndef TEST_DEFINE_CXX_AND_GNU
+# error Expected definition TEST_DEFINE_CXX_AND_GNU
+# endif
#endif
#ifndef NO_DEF_TESTS
diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt
index 2e4175442..fef83f668 100644
--- a/Tests/Complex/CMakeLists.txt
+++ b/Tests/Complex/CMakeLists.txt
@@ -446,6 +446,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
set(CMAKE_CXX_STANDARD 11)
endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
#
# Create the libs and the main exe
#
diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt
index 628cd4ec3..77baa4c32 100644
--- a/Tests/ComplexOneConfig/CMakeLists.txt
+++ b/Tests/ComplexOneConfig/CMakeLists.txt
@@ -403,6 +403,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
set(CMAKE_CXX_STANDARD 11)
endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
#
# Create the libs and the main exe
#
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
index 1b3daa6c9..a30071fd3 100644
--- a/Tests/Cuda/CMakeLists.txt
+++ b/Tests/Cuda/CMakeLists.txt
@@ -3,6 +3,7 @@ ADD_TEST_MACRO(Cuda.Complex CudaComplex)
ADD_TEST_MACRO(Cuda.ConsumeCompileFeatures CudaConsumeCompileFeatures)
ADD_TEST_MACRO(Cuda.ObjectLibrary CudaObjectLibrary)
ADD_TEST_MACRO(Cuda.MixedStandardLevels MixedStandardLevels)
+ADD_TEST_MACRO(Cuda.NotEnabled CudaNotEnabled)
ADD_TEST_MACRO(Cuda.ToolkitInclude CudaToolkitInclude)
ADD_TEST_MACRO(Cuda.ProperDeviceLibraries ProperDeviceLibraries)
ADD_TEST_MACRO(Cuda.ProperLinkFlags ProperLinkFlags)
diff --git a/Tests/Cuda/NotEnabled/CMakeLists.txt b/Tests/Cuda/NotEnabled/CMakeLists.txt
new file mode 100644
index 000000000..968751b65
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(CudaNotEnabled CXX)
+
+add_library(HasCudaProps lib.cxx)
+
+target_compile_features(HasCudaProps PUBLIC cxx_std_11)
+#Verify that setting this variables in a project that doesn't have CUDA
+#enabled allow for the project to configure and build correctly.
+#Tests the fix for #19432
+set_property(TARGET HasCudaProps PROPERTY CUDA_SEPARABLE_COMPILATION ON)
+set_property(TARGET HasCudaProps PROPERTY CUDA_RESOLVE_DEVICE_SYMBOLS ON)
+
+add_executable(CudaNotEnabled main.cxx)
+target_link_libraries(CudaNotEnabled PRIVATE HasCudaProps)
diff --git a/Tests/Cuda/NotEnabled/lib.cxx b/Tests/Cuda/NotEnabled/lib.cxx
new file mode 100644
index 000000000..5dae5a3f5
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/lib.cxx
@@ -0,0 +1,5 @@
+
+int cxx_function(int input)
+{
+ return input;
+}
diff --git a/Tests/Cuda/NotEnabled/main.cxx b/Tests/Cuda/NotEnabled/main.cxx
new file mode 100644
index 000000000..a644207a1
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/main.cxx
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+ // make sure we have c++11 enabled
+ using returnv = std::integral_constant<int, 0>;
+ return returnv::value;
+}
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
index e58204dc8..00fd7d24c 100644
--- a/Tests/CudaOnly/WithDefs/CMakeLists.txt
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -37,6 +37,8 @@ target_compile_definitions(CudaOnlyWithDefs
$<$<CONFIG:RELEASE>:$<BUILD_INTERFACE:${release_compile_defs}>>
-DDEF_COMPILE_LANG_$<COMPILE_LANGUAGE>
-DDEF_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
+ -DDEF_CUDA_COMPILER=$<CUDA_COMPILER_ID>
+ -DDEF_CUDA_COMPILER_VERSION=$<CUDA_COMPILER_VERSION>
)
target_include_directories(CudaOnlyWithDefs
diff --git a/Tests/CudaOnly/WithDefs/main.notcu b/Tests/CudaOnly/WithDefs/main.notcu
index 98f73cebd..68a296b2c 100644
--- a/Tests/CudaOnly/WithDefs/main.notcu
+++ b/Tests/CudaOnly/WithDefs/main.notcu
@@ -39,6 +39,14 @@
# error "Expected DEF_LANG_IS_CUDA"
#endif
+#ifndef DEF_CUDA_COMPILER
+# error "DEF_CUDA_COMPILER not defined!"
+#endif
+
+#ifndef DEF_CUDA_COMPILER_VERSION
+# error "DEF_CUDA_COMPILER_VERSION not defined!"
+#endif
+
static __global__ void DetermineIfValidCudaDevice()
{
}
diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in
index 8c0817cd6..b7587aa47 100644
--- a/Tests/EnforceConfig.cmake.in
+++ b/Tests/EnforceConfig.cmake.in
@@ -18,9 +18,20 @@ if(NOT CTEST_CONFIGURATION_TYPE)
endif()
endforeach()
if(NOT CTEST_CONFIGURATION_TYPE)
- set(CTEST_CONFIGURATION_TYPE NoConfig)
+ if("@CMAKE_C_COMPILER_ID@;@CMAKE_C_SIMULATE_ID@;@CMAKE_C_COMPILER_FRONTEND_VARIANT@" STREQUAL "Clang;MSVC;GNU")
+ # A valid configuration is required for this compiler in tests that do not set CMP0091 to NEW.
+ set(CTEST_CONFIGURATION_TYPE Debug)
+ else()
+ set(CTEST_CONFIGURATION_TYPE NoConfig)
+ endif()
endif()
message("Guessing configuration ${CTEST_CONFIGURATION_TYPE}")
endif()
+# Isolate tests from user configuration in the environment.
+unset(ENV{CMAKE_GENERATOR})
+unset(ENV{CMAKE_GENERATOR_INSTANCE})
+unset(ENV{CMAKE_GENERATOR_PLATFORM})
+unset(ENV{CMAKE_GENERATOR_TOOLSET})
+
@TEST_HOME_ENV_CODE@
diff --git a/Tests/ExportImport/Export/Interface/CMakeLists.txt b/Tests/ExportImport/Export/Interface/CMakeLists.txt
index fd55c423c..22a4ef600 100644
--- a/Tests/ExportImport/Export/Interface/CMakeLists.txt
+++ b/Tests/ExportImport/Export/Interface/CMakeLists.txt
@@ -41,6 +41,8 @@ install(FILES
add_library(cmakeonly INTERFACE)
set_property(TARGET cmakeonly PROPERTY INTERFACE_COMPILE_DEFINITIONS [[DEF="\"\$\B"]])
+set_property(TARGET cmakeonly PROPERTY custom_property CustomPropertyValue)
+set_property(TARGET cmakeonly PROPERTY EXPORT_PROPERTIES custom_property)
install(TARGETS headeronly sharediface use_auto_type use_c_restrict source_target
cmakeonly
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 811fff340..b5df96168 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -407,7 +407,7 @@ endforeach()
unset(_configs)
if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
- OR CMAKE_C_COMPILER_ID STREQUAL Clang)
+ OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))
AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja"))
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
diff --git a/Tests/ExportImport/Import/Interface/CMakeLists.txt b/Tests/ExportImport/Import/Interface/CMakeLists.txt
index c850508e5..a07a5b3c4 100644
--- a/Tests/ExportImport/Import/Interface/CMakeLists.txt
+++ b/Tests/ExportImport/Import/Interface/CMakeLists.txt
@@ -109,4 +109,12 @@ foreach(ns exp bld)
"not\n"
" " [[DEF="\"\$\B"]] "\n")
endif()
+ get_property(custom TARGET ${ns}::cmakeonly PROPERTY custom_property)
+ if(NOT custom STREQUAL "CustomPropertyValue")
+ message(SEND_ERROR
+ "${ns}::cmakeonly property custom_property is:\n"
+ " ${custom}\n"
+ "not\n"
+ " CustomPropertyValue\n")
+ endif()
endforeach()
diff --git a/Tests/FindBoost/CMakeLists.txt b/Tests/FindBoost/CMakeLists.txt
index 58d795ba4..8489d859c 100644
--- a/Tests/FindBoost/CMakeLists.txt
+++ b/Tests/FindBoost/CMakeLists.txt
@@ -21,7 +21,8 @@ add_test(NAME FindBoost.TestFail COMMAND
)
set_tests_properties(FindBoost.TestFail PROPERTIES
- PASS_REGULAR_EXPRESSION "Could not find the following Boost libraries:[ \t\n]+boost_foobar")
+ WILL_FAIL ON
+ PASS_REGULAR_EXPRESSION "Could NOT find Boost (missing: foobar)")
add_test(NAME FindBoost.TestHeaders COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
diff --git a/Tests/FindBoost/Test/CMakeLists.txt b/Tests/FindBoost/Test/CMakeLists.txt
index 39e92c1d3..f60ccfa00 100644
--- a/Tests/FindBoost/Test/CMakeLists.txt
+++ b/Tests/FindBoost/Test/CMakeLists.txt
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.1)
project(TestFindBoost CXX)
include(CTest)
+set(Boost_NO_BOOST_CMAKE ON)
find_package(Boost REQUIRED COMPONENTS filesystem thread
OPTIONAL_COMPONENTS program_options foobar)
diff --git a/Tests/FindCups/CMakeLists.txt b/Tests/FindCups/CMakeLists.txt
new file mode 100644
index 000000000..5be1ac106
--- /dev/null
+++ b/Tests/FindCups/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindCups.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindCups/Test"
+ "${CMake_BINARY_DIR}/Tests/FindCups/Test"
+ ${build_generator_args}
+ --build-project FindCups
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindCups/Test/CMakeLists.txt b/Tests/FindCups/Test/CMakeLists.txt
new file mode 100644
index 000000000..9e90553fb
--- /dev/null
+++ b/Tests/FindCups/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindCups C)
+include(CTest)
+
+find_package(Cups REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_CUPS_VERSION="${CUPS_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Cups::Cups)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${CUPS_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${CUPS_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindCups/Test/main.c b/Tests/FindCups/Test/main.c
new file mode 100644
index 000000000..b69d621f7
--- /dev/null
+++ b/Tests/FindCups/Test/main.c
@@ -0,0 +1,12 @@
+#include <cups/cups.h>
+
+int main()
+{
+ int num_options = 0;
+ cups_option_t* options = NULL;
+
+ num_options = cupsAddOption(CUPS_COPIES, "1", num_options, &options);
+ cupsFreeOptions(num_options, options);
+
+ return 0;
+}
diff --git a/Tests/FindEnvModules/CMakeLists.txt b/Tests/FindEnvModules/CMakeLists.txt
new file mode 100644
index 000000000..95b7d1ddb
--- /dev/null
+++ b/Tests/FindEnvModules/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_test(FindEnvModules.Test ${CMAKE_CMAKE_COMMAND}
+ -P ${CMAKE_CURRENT_LIST_DIR}/EnvModules.cmake
+)
diff --git a/Tests/FindEnvModules/EnvModules.cmake b/Tests/FindEnvModules/EnvModules.cmake
new file mode 100644
index 000000000..0c81bf21d
--- /dev/null
+++ b/Tests/FindEnvModules/EnvModules.cmake
@@ -0,0 +1,35 @@
+find_package(EnvModules REQUIRED)
+message("module purge")
+env_module(COMMAND purge RESULT_VARIABLE ret_var)
+if(NOT ret_var EQUAL 0)
+ message(FATAL_ERROR "module(purge) returned ${ret_var}")
+endif()
+
+message("module avail")
+env_module_avail(avail_mods)
+foreach(mod IN LISTS avail_mods)
+ message(" ${mod}")
+endforeach()
+
+if(avail_mods)
+ list(GET avail_mods 0 mod0)
+ message("module load ${mod0}")
+ env_module(load ${mod0})
+
+ message("module list")
+ env_module_list(loaded_mods)
+ foreach(mod IN LISTS loaded_mods)
+ message(" ${mod}")
+ endforeach()
+
+ list(LENGTH loaded_mods num_loaded_mods)
+ message("Number of modules loaded: ${num_loaded_mods}")
+ if(NOT num_loaded_mods EQUAL 1)
+ message(FATAL_ERROR "Exactly 1 module should be loaded. Found ${num_loaded_mods}")
+ endif()
+
+ list(GET loaded_mods 0 mod0_actual)
+ if(NOT (mod0_actual MATCHES "^${mod0}"))
+ message(FATAL_ERROR "Loaded module does not match ${mod0}. Actual: ${mod0_actual}")
+ endif()
+endif()
diff --git a/Tests/FindGLEW/CMakeLists.txt b/Tests/FindGLEW/CMakeLists.txt
new file mode 100644
index 000000000..ff42bcec1
--- /dev/null
+++ b/Tests/FindGLEW/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGLEW.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGLEW/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGLEW/Test"
+ ${build_generator_args}
+ --build-project TestFindGLEW
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGLEW/Test/CMakeLists.txt b/Tests/FindGLEW/Test/CMakeLists.txt
new file mode 100644
index 000000000..954ee1092
--- /dev/null
+++ b/Tests/FindGLEW/Test/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindGLEW LANGUAGES CXX)
+include(CTest)
+
+find_package(GLEW REQUIRED)
+
+add_executable(test_glew_shared_tgt main.cpp)
+target_link_libraries(test_glew_shared_tgt GLEW::GLEW)
+add_test(NAME test_glew_shared_tgt COMMAND test_glew_shared_tgt)
+
+add_executable(test_glew_generic_tgt main.cpp)
+target_link_libraries(test_glew_generic_tgt GLEW::glew)
+add_test(NAME test_glew_generic_tgt COMMAND test_glew_generic_tgt)
+
+add_executable(test_glew_var main.cpp)
+target_include_directories(test_glew_var PRIVATE ${GLEW_INCLUDE_DIRS})
+target_link_libraries(test_glew_var PRIVATE ${GLEW_LIBRARIES})
+add_test(NAME test_glew_var COMMAND test_glew_var)
diff --git a/Tests/FindGLEW/Test/main.cpp b/Tests/FindGLEW/Test/main.cpp
new file mode 100644
index 000000000..4a108ad24
--- /dev/null
+++ b/Tests/FindGLEW/Test/main.cpp
@@ -0,0 +1,8 @@
+#include <GL/glew.h>
+
+int main()
+{
+ GLenum init_return = glewInit();
+
+ return (init_return == GLEW_OK);
+}
diff --git a/Tests/FindIconv/Test/CMakeLists.txt b/Tests/FindIconv/Test/CMakeLists.txt
index c59adb3d1..a6243f53f 100644
--- a/Tests/FindIconv/Test/CMakeLists.txt
+++ b/Tests/FindIconv/Test/CMakeLists.txt
@@ -6,9 +6,11 @@ find_package(Iconv REQUIRED)
add_executable(test_iconv_tgt main.cxx)
target_link_libraries(test_iconv_tgt Iconv::Iconv)
+target_compile_features(test_iconv_tgt PRIVATE cxx_std_11)
add_test(NAME test_iconv_tgt COMMAND test_iconv_tgt)
add_executable(test_iconv_var main.cxx)
target_include_directories(test_iconv_var PRIVATE ${Iconv_INCLUDE_DIRS})
target_link_libraries(test_iconv_var PRIVATE ${Iconv_LIBRARIES})
+target_compile_features(test_iconv_var PRIVATE cxx_std_11)
add_test(NAME test_iconv_var COMMAND test_iconv_var)
diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt
index f8b36c555..da79f5d9e 100644
--- a/Tests/FindPackageTest/CMakeLists.txt
+++ b/Tests/FindPackageTest/CMakeLists.txt
@@ -205,15 +205,20 @@ if(UNIX)
message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
endif()
- # Resolve symlinks when finding the package.
- set(CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS TRUE)
- set(SetFoundResolved_DIR "")
- find_package(SetFoundResolved)
- # ./symlink points back here so it should be gone when resolved.
- set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
- if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
- message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ # This part of the test only works if there are no symlinks in our path.
+ get_filename_component(real_src_dir "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
+ if(real_src_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ # Resolve symlinks when finding the package.
+ set(CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS TRUE)
+ set(SetFoundResolved_DIR "")
+ find_package(SetFoundResolved)
+ # ./symlink points back here so it should be gone when resolved.
+ set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+ if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
+ message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ endif()
endif()
+
# Cleanup.
unset(CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS)
file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/symlink")
@@ -380,6 +385,7 @@ try_compile(EXPORTER_COMPILED
${FindPackageTest_SOURCE_DIR}/Exporter
CMakeTestExportPackage dummy
CMAKE_FLAGS "-UCMAKE_EXPORT_NO_PACKAGE_REGISTRY"
+ "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=OLD"
-Dversion=${version}
OUTPUT_VARIABLE output)
message(STATUS "Searching for export(PACKAGE) test project")
@@ -417,6 +423,25 @@ if(CMakeTestExportPackage_FOUND)
message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
endif()
+message(STATUS "Remove export(PACKAGE) test project")
+file(REMOVE_RECURSE ${FindPackageTest_BINARY_DIR}/Exporter-build)
+
+message(STATUS "Preparing export(PACKAGE) test project with POLICY CMP0090=NEW")
+try_compile(EXPORTER_COMPILED
+ ${FindPackageTest_BINARY_DIR}/Exporter-build
+ ${FindPackageTest_SOURCE_DIR}/Exporter
+ CMakeTestExportPackage dummy
+ CMAKE_FLAGS
+ "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=NEW"
+ -Dversion=${version}
+ OUTPUT_VARIABLE output)
+message(STATUS "Searching for export(PACKAGE) test project")
+find_package(CMakeTestExportPackage 1.${version} EXACT QUIET)
+if(CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
+endif()
+
+
#-----------------------------------------------------------------------------
# Test configure_package_config_file().
@@ -516,7 +541,87 @@ endif()
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
unset(SortLib_VERSION)
-
unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
set(CMAKE_PREFIX_PATH )
+
+############################################################################
+##Test FIND_PACKAGE CMAKE_FIND_PACKAGE_PREFER_CONFIG
+
+set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig)
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig)
+
+# prefer module mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+unset(ABC_FOUND)
+unset(ABC_CONFIG)
+
+find_package(ABC)
+if(NOT ABC_FOUND)
+ message(SEND_ERROR "Did not find ABC package")
+endif()
+if(ABC_CONFIG)
+ message(SEND_ERROR "Incorrectly found ABC in CONFIG mode, expected to find it with MODULE mode")
+endif()
+
+# Now prefer config mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+unset(ABC_FOUND)
+unset(ABC_CONFIG)
+
+find_package(ABC)
+if(NOT ABC_FOUND)
+ message(SEND_ERROR "Did not find ABC package")
+endif()
+if(NOT ABC_CONFIG)
+ message(SEND_ERROR "Incorrectly found ABC in MODULE mode, expected to find it with CONFIG mode")
+endif()
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+set(CMAKE_PREFIX_PATH)
+set(CMAKE_MODULE_PATH)
+
+############################################################################
+##Test FIND_PACKAGE CMAKE_FIND_PACKAGE_PREFER_CONFIG - Do not recurse
+
+# No CMAKE_PREFIX_PATH
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigRecurse)
+
+# Now prefer config mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+unset(ACME_FOUND)
+unset(ACME_CONFIG)
+
+find_package(ACME)
+if(ACME_FOUND AND ACME_CONFIG)
+ message(SEND_ERROR "Incorrectly found ACME in CONFIG mode, from the MODULE package")
+endif()
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+set(CMAKE_MODULE_PATH)
+
+############################################################################
+##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with module fallback
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigOnlyModule)
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+
+find_package(ACME REQUIRED)
+
+if(NOT ACME_FOUND)
+ message(SEND_ERROR "Did not find ACME package")
+endif()
+
+############################################################################
+##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with NO_MODULE
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigOnlyModule)
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+
+find_package(ACME NO_MODULE)
+
+if(ACME_FOUND)
+ message(SEND_ERROR "Should not find ACME package")
+endif()
diff --git a/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake
new file mode 100644
index 000000000..281a5cda9
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake
@@ -0,0 +1 @@
+set(ABC_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfig/FindABC.cmake b/Tests/FindPackageTest/PreferConfig/FindABC.cmake
new file mode 100644
index 000000000..281a5cda9
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfig/FindABC.cmake
@@ -0,0 +1 @@
+set(ABC_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake b/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake
new file mode 100644
index 000000000..7a4e1b3ce
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake
@@ -0,0 +1 @@
+set(ACME_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake b/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake
new file mode 100644
index 000000000..7a4e1b3ce
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake
@@ -0,0 +1 @@
+set(ACME_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake b/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake
new file mode 100644
index 000000000..9bdc7dbc3
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake
@@ -0,0 +1 @@
+find_package(ACME NO_MODULE)
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index 38211a4bb..4be2f22b6 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -1,12 +1,22 @@
if(CMake_TEST_FindPython)
- add_test(NAME FindPython.Python2 COMMAND
+ add_test(NAME FindPython.Python2.LOCATION COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
--build-and-test
"${CMake_SOURCE_DIR}/Tests/FindPython/Python2"
- "${CMake_BINARY_DIR}/Tests/FindPython/Python2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.LOCATION"
${build_generator_args}
--build-project TestPython2
- --build-options ${build_options}
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VERSION"
+ ${build_generator_args}
+ --build-project TestPython2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=VERSION
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
@@ -23,14 +33,24 @@ if(CMake_TEST_FindPython)
set_tests_properties(FindPython.Python2Fail PROPERTIES
PASS_REGULAR_EXPRESSION "Could NOT find Python2 \\(missing: foobar\\)")
- add_test(NAME FindPython.Python3 COMMAND
+ add_test(NAME FindPython.Python3.LOCATION COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
--build-and-test
"${CMake_SOURCE_DIR}/Tests/FindPython/Python3"
- "${CMake_BINARY_DIR}/Tests/FindPython/Python3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.LOCATION"
${build_generator_args}
--build-project TestPython3
- --build-options ${build_options}
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VERSION"
+ ${build_generator_args}
+ --build-project TestPython3
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=VERSION
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
@@ -68,6 +88,39 @@ if(CMake_TEST_FindPython)
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+
+ add_test(NAME FindPython.VirtualEnv COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnv"
+ "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnv"
+ ${build_generator_args}
+ --build-project TestVirtualEnv
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python2Embedded COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Embedded"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2Embedded"
+ ${build_generator_args}
+ --build-project TestPython2Embedded
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3Embedded COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3Embedded"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3Embedded"
+ ${build_generator_args}
+ --build-project TestPython3Embedded
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
endif()
if(CMake_TEST_FindPython_NumPy)
diff --git a/Tests/FindPython/Python/CMakeLists.txt b/Tests/FindPython/Python/CMakeLists.txt
index f7fc24368..62c805ec7 100644
--- a/Tests/FindPython/Python/CMakeLists.txt
+++ b/Tests/FindPython/Python/CMakeLists.txt
@@ -16,6 +16,9 @@ endif()
if(NOT TARGET Python::Python)
message(SEND_ERROR "Python::Python not found")
endif()
+if(NOT TARGET Python::Module)
+ message(SEND_ERROR "Python::Module not found")
+endif()
Python_add_library (spam3 MODULE ../spam.c)
target_compile_definitions (spam3 PRIVATE PYTHON3)
diff --git a/Tests/FindPython/Python2/CMakeLists.txt b/Tests/FindPython/Python2/CMakeLists.txt
index a0753f611..274745a6e 100644
--- a/Tests/FindPython/Python2/CMakeLists.txt
+++ b/Tests/FindPython/Python2/CMakeLists.txt
@@ -21,6 +21,9 @@ endif()
if(NOT TARGET Python2::Python)
message(SEND_ERROR "Python2::Python not found")
endif()
+if(NOT TARGET Python2::Module)
+ message(SEND_ERROR "Python2::Module not found")
+endif()
Python2_add_library (spam2 MODULE ../spam.c)
target_compile_definitions (spam2 PRIVATE PYTHON2)
diff --git a/Tests/FindPython/Python2Embedded/CMakeLists.txt b/Tests/FindPython/Python2Embedded/CMakeLists.txt
new file mode 100644
index 000000000..0115deaa3
--- /dev/null
+++ b/Tests/FindPython/Python2Embedded/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2Embedded C)
+
+include(CTest)
+
+find_package(Python2 REQUIRED COMPONENTS Development)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Fail to found Python 2")
+endif()
+
+if(NOT TARGET Python2::Python)
+ message(SEND_ERROR "Python2::Python not found")
+endif()
+
+Python2_add_library (display_time2 SHARED ../display_time.c)
+set_property (TARGET display_time2 PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
+target_compile_definitions (display_time2 PRIVATE PYTHON2)
+
+add_executable (main2 ../main.c)
+target_link_libraries (main2 PRIVATE display_time2)
+
+if (WIN32 OR CYGWIN OR MSYS OR MINGW)
+ list (JOIN Python2_RUNTIME_LIBRARY_DIRS "$<SEMICOLON>" RUNTIME_DIRS)
+ add_test (NAME Python2.Embedded COMMAND "${CMAKE_COMMAND}" -E env "PATH=${RUNTIME_DIRS}" $<TARGET_FILE:main2>)
+else()
+ add_test (NAME Python2.Embedded COMMAND main2)
+endif()
+set_property (TEST Python2.Embedded PROPERTY PASS_REGULAR_EXPRESSION "Today is")
diff --git a/Tests/FindPython/Python3/CMakeLists.txt b/Tests/FindPython/Python3/CMakeLists.txt
index 65eea4c27..b21a15bc8 100644
--- a/Tests/FindPython/Python3/CMakeLists.txt
+++ b/Tests/FindPython/Python3/CMakeLists.txt
@@ -21,6 +21,9 @@ endif()
if(NOT TARGET Python3::Python)
message(SEND_ERROR "Python2::Python not found")
endif()
+if(NOT TARGET Python3::Module)
+ message(SEND_ERROR "Python2::Module not found")
+endif()
Python3_add_library (spam3 MODULE ../spam.c)
target_compile_definitions (spam3 PRIVATE PYTHON3)
diff --git a/Tests/FindPython/Python3Embedded/CMakeLists.txt b/Tests/FindPython/Python3Embedded/CMakeLists.txt
new file mode 100644
index 000000000..4eb7ebc14
--- /dev/null
+++ b/Tests/FindPython/Python3Embedded/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3Embedded C)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Development)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Fail to found Python 3")
+endif()
+
+if(NOT TARGET Python3::Python)
+ message(SEND_ERROR "Python3::Python not found")
+endif()
+
+Python3_add_library (display_time3 SHARED ../display_time.c)
+set_property (TARGET display_time3 PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
+target_compile_definitions (display_time3 PRIVATE PYTHON3)
+
+add_executable (main3 ../main.c)
+target_link_libraries (main3 PRIVATE display_time3)
+
+if (WIN32 OR CYGWIN OR MSYS OR MINGW)
+ list (JOIN Python3_RUNTIME_LIBRARY_DIRS "$<SEMICOLON>" RUNTIME_DIRS)
+ add_test (NAME Python3.Embedded COMMAND "${CMAKE_COMMAND}" -E env "PATH=${RUNTIME_DIRS}" $<TARGET_FILE:main3>)
+else()
+ add_test (NAME Python3.Embedded COMMAND main3)
+endif()
+set_property (TEST Python3.Embedded PROPERTY PASS_REGULAR_EXPRESSION "Today is")
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
new file mode 100644
index 000000000..64ba20186
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnv LANGUAGES NONE)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Fail to found Python 3")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+
+execute_process (COMMAND "${Python3_EXECUTABLE}" -m venv "${Python3_VIRTUAL_ENV}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE outputs
+ ERROR_VARIABLE outputs)
+if (result)
+ message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefault
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandard
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
new file mode 100644
index 000000000..020ecacd9
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
new file mode 100644
index 000000000..29a49249c
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+ message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+ message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
new file mode 100644
index 000000000..89f27d8da
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()
diff --git a/Tests/FindPython/display_time.c b/Tests/FindPython/display_time.c
new file mode 100644
index 000000000..0e7843422
--- /dev/null
+++ b/Tests/FindPython/display_time.c
@@ -0,0 +1,36 @@
+
+#include <stdio.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "display_time.h"
+
+void display_time()
+{
+#if defined(PYTHON3)
+ wchar_t* program = Py_DecodeLocale("display_time", NULL);
+ if (program == NULL) {
+ fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
+ exit(1);
+ }
+ char* cmd = "from time import time,ctime\n"
+ "print('Today is', ctime(time()))\n";
+#else
+ char* program = "display_time";
+ char* cmd = "from time import time,ctime\n"
+ "print 'Today is', ctime(time())\n";
+#endif
+
+ Py_SetProgramName(program); /* optional but recommended */
+ Py_Initialize();
+ PyRun_SimpleString(cmd);
+#if defined(PYTHON3)
+ if (Py_FinalizeEx() < 0) {
+ exit(120);
+ }
+ PyMem_RawFree(program);
+#else
+ Py_Finalize();
+#endif
+}
diff --git a/Tests/FindPython/display_time.h b/Tests/FindPython/display_time.h
new file mode 100644
index 000000000..d825e0273
--- /dev/null
+++ b/Tests/FindPython/display_time.h
@@ -0,0 +1,2 @@
+
+void display_time();
diff --git a/Tests/FindPython/main.c b/Tests/FindPython/main.c
new file mode 100644
index 000000000..0acba2917
--- /dev/null
+++ b/Tests/FindPython/main.c
@@ -0,0 +1,7 @@
+
+#include "display_time.h"
+
+int main()
+{
+ display_time();
+}
diff --git a/Tests/Fortran/CMakeLists.txt b/Tests/Fortran/CMakeLists.txt
index 7023615f2..929fa4ddf 100644
--- a/Tests/Fortran/CMakeLists.txt
+++ b/Tests/Fortran/CMakeLists.txt
@@ -46,7 +46,7 @@ function(test_fortran_c_interface_module)
FortranCInterface_VERIFY()
FortranCInterface_VERIFY(CXX)
if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
- if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|MIPSpro|PathScale|Absoft")
+ if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|PathScale|Absoft")
set(module_expected 1)
endif()
if(FortranCInterface_MODULE_FOUND OR module_expected)
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 3d0870484..3ff2b8595 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -3,11 +3,26 @@ project(GeneratorExpression)
include(CTest)
+# Real projects normally want the MSYS shell path conversion, but for this test
+# we need to verify that the command line is constructed with the proper string.
+set(msys1_prefix "")
+set(msys2_no_conv "")
+if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+ execute_process(COMMAND "uname" OUTPUT_VARIABLE uname)
+ if("${uname}" MATCHES "^MINGW32")
+ # MinGW.org MSYS 1.0 does not support generic path conversion suppression
+ set(msys1_prefix MSYS1_PREFIX)
+ else()
+ # msys2 supports generic path conversion suppression
+ set(msys2_no_conv env MSYS2_ARG_CONV_EXCL=-D)
+ endif()
+endif()
+
# This test is split into multiple parts as needed to avoid NMake command
# length limits.
add_custom_target(check-part1 ALL
- COMMAND ${CMAKE_COMMAND}
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
-Dtest_0=$<0:nothing>
-Dtest_0_with_comma=$<0:-Wl,--no-undefined>
-Dtest_1=$<1:content>
@@ -97,7 +112,7 @@ add_library(empty5 empty.cpp)
target_include_directories(empty5 PRIVATE /empty5/private1 /empty5/private2)
add_custom_target(check-part2 ALL
- COMMAND ${CMAKE_COMMAND}
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
-Dtest_incomplete_1=$<
-Dtest_incomplete_2=$<something
-Dtest_incomplete_3=$<something:
@@ -188,7 +203,7 @@ set_property(TARGET importedFallback PROPERTY MAP_IMPORTED_CONFIG_DEBUG "" DEBUG
set_property(TARGET importedFallback PROPERTY MAP_IMPORTED_CONFIG_RELEASE "")
add_custom_target(check-part3 ALL
- COMMAND ${CMAKE_COMMAND}
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
-Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1>
-Dtest_version_greater_2=$<VERSION_GREATER:1.1.1,1.0>
-Dtest_version_less_1=$<VERSION_LESS:1.1.1,1.0>
@@ -205,6 +220,7 @@ add_custom_target(check-part3 ALL
-Dtest_early_termination_2=$<$<1:>:,
-Dsystem_name=${CMAKE_HOST_SYSTEM_NAME}
-Dtest_platform_id=$<PLATFORM_ID>
+ -Dtest_platform_id_supported=$<PLATFORM_ID:Linux,Windows,Darwin>
-Dtest_platform_id_Linux=$<PLATFORM_ID:Linux>
-Dtest_platform_id_Windows=$<PLATFORM_ID:Windows>
-Dtest_platform_id_Darwin=$<PLATFORM_ID:Darwin>
@@ -241,17 +257,19 @@ add_custom_target(check-part3 ALL
if(WIN32)
set(test_shell_path c:/shell/path)
+ set(test_shell_path2 c:/shell/path d:/another/path)
else()
set(test_shell_path /shell/path)
+ set(test_shell_path2 /shell/path /another/path)
endif()
-set(path_prefix BYPASS_FURTHER_CONVERSION)
add_custom_target(check-part4 ALL
- COMMAND ${CMAKE_COMMAND}
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
# Prefix path to bypass its further conversion when being processed by
# CMake as command-line argument
- -Dtest_shell_path=${path_prefix}$<SHELL_PATH:${test_shell_path}>
- -Dpath_prefix=${path_prefix}
+ -Dmsys1_prefix=${msys1_prefix}
+ -Dtest_shell_path=${msys1_prefix}$<SHELL_PATH:${test_shell_path}>
+ "-Dtest_shell_path2=$<SHELL_PATH:${test_shell_path2}>"
-Dif_1=$<IF:1,a,b>
-Dif_2=$<IF:0,a,b>
-Dif_3=$<IF:$<EQUAL:10,30>,a,b>
@@ -357,4 +375,49 @@ if(NOT CMAKE_GENERATOR STREQUAL Xcode OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;
-P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
DEPENDS objlib
)
+
+
+ add_library(sharedlib SHARED objlib1.c objlib2.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:sharedlib>,\n>\n"
+ )
+
+ add_custom_target(check_sharedlib_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS sharedlib
+ )
+
+
+ add_library(staticlib STATIC objlib1.c objlib2.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:staticlib>,\n>\n"
+ )
+
+ add_custom_target(check_staticlib_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS staticlib
+ )
+
+
+ add_executable(execobjs objlib1.c objlib2.c echo.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:execobjs>,\n>\n"
+ )
+
+ add_custom_target(check_exec_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=3
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS execobjs
+ )
endif()
diff --git a/Tests/GeneratorExpression/check-part3.cmake b/Tests/GeneratorExpression/check-part3.cmake
index 9014406c2..4fb730887 100644
--- a/Tests/GeneratorExpression/check-part3.cmake
+++ b/Tests/GeneratorExpression/check-part3.cmake
@@ -28,11 +28,16 @@ check(test_early_termination_2 "$<:,")
check(test_platform_id "${system_name}")
foreach(system Linux Windows Darwin)
if(system_name STREQUAL system)
+ check(test_platform_id_supported 1)
check(test_platform_id_${system} 1)
+ set(platform_supported 1)
else()
check(test_platform_id_${system} 0)
endif()
endforeach()
+if(NOT platform_supported)
+ check(test_platform_id_supported 0)
+endif()
check(lower_case "mi,xed")
check(upper_case "MIX,ED")
check(make_c_identifier "_4f_oo__bar__")
diff --git a/Tests/GeneratorExpression/check-part4.cmake b/Tests/GeneratorExpression/check-part4.cmake
index f5d14dd45..a7e09445e 100644
--- a/Tests/GeneratorExpression/check-part4.cmake
+++ b/Tests/GeneratorExpression/check-part4.cmake
@@ -1,6 +1,8 @@
include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
-string(REPLACE ${path_prefix} "" test_shell_path ${test_shell_path})
+if(msys1_prefix)
+ string(REPLACE "${msys1_prefix}" "" test_shell_path ${test_shell_path})
+endif()
if(WIN32)
if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
@@ -13,6 +15,17 @@ if(WIN32)
else()
check(test_shell_path [[/shell/path]])
endif()
+if(WIN32)
+ if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles" AND NOT msys1_prefix)
+ check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+ elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ check(test_shell_path2 [[c:/shell/path;d:/another/path]])
+ else()
+ check(test_shell_path2 [[c:\shell\path;d:\another\path]])
+ endif()
+else()
+ check(test_shell_path2 [[/shell/path:/another/path]])
+endif()
check(if_1 "a")
check(if_2 "b")
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
new file mode 100644
index 000000000..93d668bb6
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
@@ -0,0 +1,110 @@
+# 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.12 FATAL_ERROR)
+
+project(test C)
+
+# Tests assume no previous builds in the build directory
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/build)
+
+macro (test_output)
+ if (BUILD_OUTPUT STREQUAL EXPECTED_LINES )
+ message("Build OK")
+ else()
+ message("BUILD_OUTPUT")
+ foreach(Line IN LISTS BUILD_OUTPUT)
+ message("${Line}")
+ endforeach()
+ message("EXPECTED_LINES")
+ foreach(Line IN LISTS EXPECTED_LINES)
+ message("${Line}")
+ endforeach()
+ message(SEND_ERROR "Build KO")
+ endif()
+endmacro()
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib1.c
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building ALL target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_postbuild")
+
+test_output()
+
+message("Building target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate C file another_file")
+list(APPEND EXPECTED_LINES "CT: generate text file dependsA")
+list(APPEND EXPECTED_LINES "CT: generate text file out_of_order_dep")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
+
+message("Rerun target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
new file mode 100644
index 000000000..fed946cc5
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
@@ -0,0 +1,108 @@
+# 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.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+
+set(TEST_MISSING_TARGET_SRC 0)
+set(TEST_MISSING_TARGET_DEP 0)
+set(TEST_MISSING_DEP 0)
+set(TEST_DEP_CYCLE 0)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_custom_target(target_cmd ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd" > target_cmd
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_extra" > target_cmd_extra.txt
+ BYPRODUCTS target_cmd target_cmd_extra.txt
+ COMMENT "CT: Processing target_cmd")
+
+add_custom_command(TARGET target_cmd PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prebuild" > target_cmd_prebuild.txt
+ BYPRODUCTS target_cmd_prebuild.txt
+ COMMENT "CT: Processing target_cmd_prebuild")
+#event does not run for custom targets
+add_custom_command(TARGET target_cmd PRE_LINK
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_prelink commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prelink" > target_cmd_prelink.txt
+ BYPRODUCTS target_cmd_prelink.txt
+ COMMENT "CT: Processing target_cmd_prelink")
+add_custom_command(TARGET target_cmd POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_postbuild commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_postbuild" > target_cmd_postbuild.txt
+ BYPRODUCTS target_cmd_postbuild.txt
+ COMMENT "CT: Processing target_cmd_postbuild")
+
+add_custom_target(target_empty ALL
+ COMMENT "CT: Processing target_empty")
+
+add_custom_command(TARGET target_empty PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_prebuild" > target_empty_prebuild.txt
+ BYPRODUCTS target_empty_prebuild.txt
+ COMMENT "CT: Processing target_empty_prebuild")
+add_custom_command(TARGET target_empty POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_postbuild" > target_empty_postbuild.txt
+ BYPRODUCTS target_empty_postbuild.txt
+ COMMENT "CT: Processing target_empty_postbuild")
+
+add_dependencies(target_cmd target_empty)
+
+add_custom_command(
+ OUTPUT out_of_order_dep.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "out_of_order_dep" > out_of_order_dep.txt
+ COMMENT "CT: generate text file out_of_order_dep"
+ DEPENDS dependsA.txt
+)
+
+if(TEST_MISSING_TARGET_SRC)
+ set(SRC_FILE does_not_exist)
+endif()
+if(TEST_MISSING_TARGET_DEP)
+ set(DEP_FILE does_not_exist)
+endif()
+
+add_custom_target(target_update_files
+ DEPENDS genc_do_not_list.txt ${DEP_FILE}
+ SOURCES gena.txt genb.txt another_file.c ${SRC_FILE}
+ BYPRODUCTS junkit.txt
+ COMMAND ${CMAKE_COMMAND} -E copy another_file.c junkit.txt
+ COMMENT "CT: Processing target_update_files")
+
+add_custom_command(
+ OUTPUT force_rebuild gena.txt genb.txt genc_do_not_list.txt
+ COMMAND ${CMAKE_COMMAND} -E copy dependsA.txt gena.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genb" > genb.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genc" > genc_do_not_list.txt
+ DEPENDS out_of_order_dep.txt dependsA.txt
+ COMMENT "CT: generate text files A, B, and C"
+)
+
+if(TEST_MISSING_DEP)
+ set(MISSING_DEP MISSING_DEP)
+endif()
+if(TEST_DEP_CYCLE)
+ set(DEP_CYCLE out_of_order_dep.txt)
+endif()
+
+add_custom_command(
+ OUTPUT dependsA.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "dependsA" > dependsA.txt
+ DEPENDS ${MISSING_DEP} ${DEP_CYCLE} another_file.c
+ COMMENT "CT: generate text file dependsA"
+)
+
+add_custom_command(
+ OUTPUT another_file.c
+ COMMAND ${CMAKE_COMMAND} -E echo "//auto-gen file" > another_file.c
+ COMMENT "CT: generate C file another_file"
+)
+
+add_dependencies(target_update_files target_empty)
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
new file mode 100644
index 000000000..29ad70a3b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
new file mode 100644
index 000000000..b35e9cc5e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
new file mode 100644
index 000000000..2e2871b11
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
@@ -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.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+#set_property( GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+add_subdirectory(exec)
+add_subdirectory(lib)
+add_subdirectory(protolib)
+add_dependencies(lib1 proto)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
new file mode 100644
index 000000000..85ee8056b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
@@ -0,0 +1,11 @@
+# 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.12 FATAL_ERROR)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+target_include_directories(exe1 PRIVATE "${test_BINARY_DIR}")
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
new file mode 100644
index 000000000..fbf4ed43e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
@@ -0,0 +1,8 @@
+#include "lib1.h"
+#include "p.h"
+
+int main(void)
+{
+ return func1() + func2() + func3() + func1p() + func2p() + func3p() +
+ PROTO1 + PROTO2 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
new file mode 100644
index 000000000..ae30fa2bd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
@@ -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.
+
+add_library(lib1 STATIC
+ func1.c lib1.h
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h")
+set_source_files_properties(
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h"
+ PROPERTIES GENERATED 1)
+target_include_directories(lib1 PRIVATE "${test_BINARY_DIR}/protolib"
+ PUBLIC .)
+add_custom_command( TARGET lib1 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${test_BINARY_DIR}/protolib/proto1.h" "${test_BINARY_DIR}/p.h"
+ COMMENT "Copy ${test_BINARY_DIR}/protolib/proto1.h ${test_BINARY_DIR}/p.h"
+ BYPRODUCTS "${test_BINARY_DIR}/p.h")
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
new file mode 100644
index 000000000..53334fe36
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
@@ -0,0 +1,17 @@
+#include "lib1.h"
+#include "proto1.h"
+
+int func1(void)
+{
+ return 1 + PROTO1;
+}
+
+int func2(void)
+{
+ return 2 + PROTO2;
+}
+
+int func3(void)
+{
+ return 3 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
new file mode 100644
index 000000000..5e99f0287
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
@@ -0,0 +1,3 @@
+extern int func1(void);
+extern int func2(void);
+extern int func3(void);
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
new file mode 100644
index 000000000..8cb6869bd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
@@ -0,0 +1,28 @@
+# 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.12 FATAL_ERROR)
+
+add_custom_target(proto ALL
+ DEPENDS proto1.c
+ proto1.h
+ SOURCES
+ ${test_SOURCE_DIR}/protolib/proto1.c.in
+ ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "Creating proto files")
+
+add_custom_command(
+ OUTPUT proto1.c
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.c.in proto1.c
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.c.in
+ COMMENT "generate proto C files"
+)
+
+add_custom_command(
+ OUTPUT proto1.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.h.in proto1.h
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "generate proto H files"
+)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
new file mode 100644
index 000000000..0efb1bd8d
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
@@ -0,0 +1,16 @@
+#include "proto1.h"
+
+int func1p(void)
+{
+ return 1;
+}
+
+int func2p(void)
+{
+ return 2;
+}
+
+int func3p(void)
+{
+ return 3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
new file mode 100644
index 000000000..f2f93afdd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
@@ -0,0 +1,7 @@
+extern int func1p(void);
+extern int func2p(void);
+extern int func3p(void);
+
+#define PROTO1 0x1
+#define PROTO2 0x2
+#define PROTO3 0x3
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
new file mode 100644
index 000000000..24126c8fa
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
@@ -0,0 +1,14 @@
+# 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.12 FATAL_ERROR)
+
+project(test C)
+include(ExternalProject)
+
+ExternalProject_Add(another_project
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/empty
+ BINARY_DIR empty_build
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
new file mode 100644
index 000000000..6846a9853
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
@@ -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.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(empty NONE)
+
+message("EMPTY PROJECT")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
index e431217aa..3837b5a2e 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
@@ -1,4 +1,3 @@
add_executable(App Main.c)
-target_include_directories(App PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
target_link_libraries(App Lib)
target_compile_options(App PUBLIC "-non_shared")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
index 00e0f59b8..bb9849abb 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
@@ -1 +1,2 @@
add_library(Lib HelperFun.c HelperFun.h)
+target_include_directories(Lib PUBLIC .)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
index c5db1551a..3f2f0eba6 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
@@ -18,3 +18,4 @@ target_link_options(kernel PRIVATE -kernel)
# create monolith INTEGRITY application
add_executable(monolith test.int)
+add_dependencies(monolith vas)
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
index a025814ed..98668e5c9 100644
--- a/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(test C)
-add_library(obj1 OBJECT testObj.c testObj.h sub/testObj.c testObj2.c)
+add_library(obj1 OBJECT testOBJ.c testOBJ.h sub/testOBJ.c testOBJ2.c)
add_executable(exe1 exe.c $<TARGET_OBJECTS:obj1>)
if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
diff --git a/Tests/GhsMulti/GhsMultiPlatform/file1.c b/Tests/GhsMulti/GhsMultiPlatform/file1.c
deleted file mode 100644
index 4132aa406..000000000
--- a/Tests/GhsMulti/GhsMultiPlatform/file1.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(void)
-{
- return -42;
-}
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
index f5792b405..b2540d974 100644
--- a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
@@ -13,7 +13,7 @@ endif()
if(RUN_TEST STREQUAL "SINGLE_EXEC")
add_executable(exe1 exe.c)
- set(targets_to_install ${targets_to_install} exe1)
+ set(targets_to_install exe1)
endif()
if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
@@ -22,7 +22,7 @@ if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
set_property(TARGET exe1 PROPERTY RUNTIME_OUTPUT_DIRECTORY ${name}_bin_$<CONFIG>)
set_property(TARGET exe1 PROPERTY OUTPUT_NAME ${name}_$<CONFIG>)
set_property(TARGET exe1 PROPERTY SUFFIX .bin)
- set(targets_to_install ${targets_to_install} exe1)
+ set(targets_to_install exe1)
endif()
if(RUN_TEST STREQUAL "EXEC_AND_LIB")
@@ -33,7 +33,7 @@ if(RUN_TEST STREQUAL "EXEC_AND_LIB")
add_executable(exe1 exe1.c)
target_link_libraries(exe1 lib1)
- set(targets_to_install ${targets_to_install} exe1 lib1)
+ set(targets_to_install exe1 lib1)
endif()
install(TARGETS ${targets_to_install}
diff --git a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
index ed3094b02..f5f3c55fd 100644
--- a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
@@ -5,8 +5,6 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(test C)
-add_custom_target(testTarget ALL echo this is a test)
-
add_library(sharedLib SHARED file.c)
add_library(moduleLib MODULE file.c)
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index b7b8320bc..761c405b1 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.6)
project(IncludeDirectories)
if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
- OR CMAKE_C_COMPILER_ID STREQUAL Clang OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
+ OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles"
OR CMAKE_GENERATOR STREQUAL "Ninja"
OR (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT XCODE_VERSION VERSION_LESS 6.0)))
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
index 5b99ea7b3..a9edf9a97 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
@@ -17,7 +17,8 @@ create_header(bing)
create_header(bung)
create_header(arguments)
create_header(list)
-create_header(target)
+create_header(target1)
+create_header(target2)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
@@ -69,14 +70,23 @@ set_property(TARGET lib4 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BI
set_property(TARGET lib4 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>")
add_library(somelib::withcolons UNKNOWN IMPORTED)
-set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target")
-set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target")
+set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target1")
+set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target1")
set_property(TARGET TargetIncludeDirectories
APPEND PROPERTY INCLUDE_DIRECTORIES
"$<TARGET_PROPERTY:somelib::withcolons,INTERFACE_INCLUDE_DIRECTORIES>"
)
+add_library(somelib_aliased UNKNOWN IMPORTED GLOBAL)
+set_property(TARGET somelib_aliased PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target2")
+add_library(somelib::withcolons2 ALIAS somelib_aliased)
+
+set_property(TARGET TargetIncludeDirectories
+ APPEND PROPERTY INCLUDE_DIRECTORIES
+ "$<TARGET_PROPERTY:somelib::withcolons2,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
add_custom_target(test_custom_target
"some_bogus_custom_tool"
$<TARGET_PROPERTY:TargetIncludeDirectories,COMPILE_DEFINITIONS>
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
index 2ee05e2ee..541ef92c2 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
@@ -10,7 +10,8 @@
#include "foo.h"
#include "list.h"
#include "prefix_foo_bar_bat.h"
-#include "target.h"
+#include "target1.h"
+#include "target2.h"
#include "ting.h"
int main(int, char**)
diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
new file mode 100644
index 000000000..f7d9fec2e
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
@@ -0,0 +1,71 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibrary)
+
+if(CMake_TEST_CUDA)
+ enable_language(CUDA)
+endif()
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that try_compile builds with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "${rtl}")
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${verify_tc_config_${dbg}}")
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+ try_compile(${rtl}_COMPILES
+ ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${rtl}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+ COMPILE_DEFINITIONS ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}}
+ OUTPUT_VARIABLE ${rtl}_OUTPUT
+ )
+ if(${rtl}_COMPILES)
+ message(STATUS "try_compile with ${rtl} worked")
+ else()
+ string(REPLACE "\n" "\n " ${rtl}_OUTPUT " ${${rtl}_OUTPUT}")
+ message(SEND_ERROR "try_compile with ${rtl} failed:\n${${rtl}_OUTPUT}")
+ endif()
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+
+ verify_combinations(MultiThreaded ${lang} ${src})
+
+ # Test known MSVC default behavior when no flag is given.
+ if(CMAKE_${lang}_COMPILER_ID STREQUAL "MSVC")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "")
+ add_library(empty-${lang} ${src})
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
+ # VS 2005 and above default to multi-threaded.
+ target_compile_definitions(empty-${lang} PRIVATE VERIFY_MT)
+ endif()
+ if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+ # VS 2010 and above have a different default runtime library for projects than 'cl'.
+ target_compile_definitions(empty-${lang} PRIVATE VERIFY_DLL)
+ endif()
+ endif()
+endfunction()
+
+verify(C verify.c)
+verify(CXX verify.cxx)
+if(CMake_TEST_CUDA)
+ verify(CUDA verify.cu)
+endif()
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
new file mode 100644
index 000000000..169ba07d3
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibraryFortran Fortran)
+
+foreach(t MultiThreaded SingleThreaded)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${t}${dbg}${dll}")
+ # ifort does not actually define these, so inject them
+ string(REPLACE "-threads" "-threads;-D_MT" "${var}" "${${var}}")
+ string(REPLACE "-dbglibs" "-dbglibs;-D_DEBUG" "${var}" "${${var}}")
+ endforeach()
+ endforeach()
+endforeach()
+string(APPEND CMAKE_Fortran_FLAGS " -w")
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+ verify_combinations(MultiThreaded ${lang} ${src})
+endfunction()
+
+verify(Fortran verify.F90)
+# 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")
+ verify_combinations(SingleThreaded Fortran verify.F90)
+endif()
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
new file mode 100644
index 000000000..6fe5e0553
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
@@ -0,0 +1 @@
+#include "../verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.c b/Tests/MSVCRuntimeLibrary/verify.c
new file mode 100644
index 000000000..741bca6b8
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.c
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.cu b/Tests/MSVCRuntimeLibrary/verify.cu
new file mode 100644
index 000000000..741bca6b8
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.cu
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.cxx b/Tests/MSVCRuntimeLibrary/verify.cxx
new file mode 100644
index 000000000..741bca6b8
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.cxx
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.h b/Tests/MSVCRuntimeLibrary/verify.h
new file mode 100644
index 000000000..58d65fe32
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.h
@@ -0,0 +1,29 @@
+#ifdef VERIFY_DEBUG
+# ifndef _DEBUG
+# error "_DEBUG not defined by debug runtime library selection"
+# endif
+#else
+# ifdef _DEBUG
+# error "_DEBUG defined by non-debug runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_DLL
+# ifndef _DLL
+# error "_DLL not defined by DLL runtime library selection"
+# endif
+#else
+# ifdef _DLL
+# error "_DLL defined by non-DLL runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_MT
+# ifndef _MT
+# error "_MT not defined by multi-threaded runtime library selection"
+# endif
+#else
+# ifdef _MT
+# error "_MT defined by single-threaded runtime library selection"
+# endif
+#endif
diff --git a/Tests/MakeClean/ToClean/CMakeLists.txt b/Tests/MakeClean/ToClean/CMakeLists.txt
index d0e24cefe..6f16d129f 100644
--- a/Tests/MakeClean/ToClean/CMakeLists.txt
+++ b/Tests/MakeClean/ToClean/CMakeLists.txt
@@ -1,42 +1,110 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 3.14)
project(ToClean)
-# Build a simple project.
-add_executable(toclean toclean.cxx)
+# Utility variables
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+set(CLEAN_FILE_CONTENT "File registered for cleaning.\n")
+
+# Lists build-time-generated files that should be cleaned away
+set_property(GLOBAL PROPERTY TOCLEAN_FILES "")
+function(addCleanFile FILENAME)
+ set_property(GLOBAL APPEND PROPERTY TOCLEAN_FILES "${FILENAME}")
+endfunction()
+function(writeCleanFile FILENAME)
+ file(WRITE "${FILENAME}" ${CLEAN_FILE_CONTENT})
+endfunction()
-# List some build-time-generated files.
-set(TOCLEAN_FILES ${TOCLEAN_FILES}
- "${ToClean_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toclean.dir/toclean.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
+# Build a simple project whose compiled objects should be cleaned.
+add_executable(toclean toclean.cxx)
+addCleanFile("${CBD}${CMAKE_FILES_DIRECTORY}/toclean.dir/toclean.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
-# Create a file that must be registered for cleaning.
-file(WRITE "${ToClean_BINARY_DIR}/Registered.txt"
- "File registered for cleaning.\n")
-set_directory_properties(PROPERTIES
- ADDITIONAL_MAKE_CLEAN_FILES "${ToClean_BINARY_DIR}/Registered.txt")
-set(TOCLEAN_FILES ${TOCLEAN_FILES} "${ToClean_BINARY_DIR}/Registered.txt")
+# Create a post build custom command that copies the toclean output executable
+# to a custom location
+function(addToCleanPostBuildCopy FILENAME)
+ add_custom_command(TARGET toclean POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy $<TARGET_FILE:toclean> ${FILENAME})
+endfunction()
# Create a custom command whose output should be cleaned.
-add_custom_command(OUTPUT ${ToClean_BINARY_DIR}/generated.txt
- DEPENDS ${ToClean_SOURCE_DIR}/toclean.cxx
+set(CustomCommandFile "${CBD}/CustomCommandFile.txt")
+add_custom_command(OUTPUT ${CustomCommandFile}
+ DEPENDS ${CSD}/toclean.cxx
COMMAND ${CMAKE_COMMAND}
- ARGS -E copy ${ToClean_SOURCE_DIR}/toclean.cxx
- ${ToClean_BINARY_DIR}/generated.txt
- )
-add_custom_target(generate ALL DEPENDS ${ToClean_BINARY_DIR}/generated.txt)
-set(TOCLEAN_FILES ${TOCLEAN_FILES} "${ToClean_BINARY_DIR}/generated.txt")
+ ARGS -E copy ${CSD}/toclean.cxx ${CustomCommandFile})
+add_custom_target(generate ALL DEPENDS ${CustomCommandFile})
+addCleanFile(${CustomCommandFile})
+
+
+### Tests ADDITIONAL_MAKE_CLEAN_FILES directory property
+if("${CMAKE_GENERATOR}" MATCHES "Makefile")
+ # Create a file that must be registered for cleaning.
+ set(MakeDirPropFile "${CBD}/MakeDirPropFile.txt")
+ writeCleanFile("${MakeDirPropFile}")
+ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${MakeDirPropFile}")
+ addCleanFile(${MakeDirPropFile})
+
+ # Create a custom command whose output should be cleaned, but whose name
+ # is not known until generate-time
+ set(MakeDirPropExpFileRel "MakeDirProp_copy${CMAKE_EXECUTABLE_SUFFIX}")
+ set(MakeDirPropExpFile "$<TARGET_FILE_DIR:toclean>/${MakeDirPropExpFileRel}")
+ addToCleanPostBuildCopy("${MakeDirPropExpFile}")
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${MakeDirPropExpFile})
+ addCleanFile("${CBD}/${MakeDirPropExpFileRel}")
+endif()
+
+
+### Tests ADDITIONAL_CLEAN_FILES directory property
+
+# Register a file path relative to the build directory
+set(DirPropFileRel "DirPropFileRel.txt")
+writeCleanFile("${CBD}/${DirPropFileRel}")
+set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${DirPropFileRel})
+addCleanFile("${CBD}/${DirPropFileRel}")
+
+# Register an absolute file path
+set(DirPropFileAbs "${CBD}/DirPropFileAbs.txt")
+writeCleanFile("${DirPropFileAbs}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropFileAbs})
+addCleanFile("${DirPropFileAbs}")
# Create a custom command whose output should be cleaned, but whose name
# is not known until generate-time
-set(copied_exe "$<TARGET_FILE_DIR:toclean>/toclean_copy${CMAKE_EXECUTABLE_SUFFIX}")
-add_custom_command(TARGET toclean POST_BUILD
- COMMAND ${CMAKE_COMMAND}
- ARGS -E copy $<TARGET_FILE:toclean>
- ${copied_exe}
- )
-set_property(DIRECTORY APPEND PROPERTY
- ADDITIONAL_MAKE_CLEAN_FILES ${copied_exe})
-list(APPEND TOCLEAN_FILES "${ToClean_BINARY_DIR}/toclean_copy${CMAKE_EXECUTABLE_SUFFIX}")
+set(DirPropExpFileRel "DirProp_copy${CMAKE_EXECUTABLE_SUFFIX}")
+set(DirPropExpFile "$<TARGET_FILE_DIR:toclean>/${DirPropExpFileRel}")
+addToCleanPostBuildCopy("${DirPropExpFile}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropExpFile})
+addCleanFile("${CBD}/${DirPropExpFileRel}")
+
+
+### Tests ADDITIONAL_CLEAN_FILES target property
+
+# Register a file path relative to the build directory
+set(TgtPropFileRel "TargetPropFileRel.txt")
+writeCleanFile("${CBD}/${TgtPropFileRel}")
+set_target_properties(toclean PROPERTIES ADDITIONAL_CLEAN_FILES ${TgtPropFileRel})
+addCleanFile("${CBD}/${TgtPropFileRel}")
+
+# Register an absolute file path
+set(TgtPropFileAbs "${CBD}/TargetPropFileAbs.txt")
+writeCleanFile("${TgtPropFileAbs}")
+set_property(TARGET toclean APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${TgtPropFileAbs})
+addCleanFile("${TgtPropFileAbs}")
+
+# Create a custom command whose output should be cleaned, but whose name
+# is not known until generate-time
+set(TgtPropExpFileRel "TgtProp_copy${CMAKE_EXECUTABLE_SUFFIX}")
+set(TgtPropExpFile "$<TARGET_FILE_DIR:toclean>/${TgtPropExpFileRel}")
+addToCleanPostBuildCopy("${TgtPropExpFile}")
+set_property(TARGET toclean APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${TgtPropExpFile})
+addCleanFile("${CBD}/${TgtPropExpFileRel}")
+
+
+# Process subdirectory without targets
+add_subdirectory(EmptySubDir)
+
# Configure a file listing these build-time-generated files.
-configure_file(${ToClean_SOURCE_DIR}/ToCleanFiles.cmake.in
- ${ToClean_BINARY_DIR}/ToCleanFiles.cmake @ONLY)
+get_property(TOCLEAN_FILES GLOBAL PROPERTY TOCLEAN_FILES)
+configure_file(${CSD}/ToCleanFiles.cmake.in ${CBD}/ToCleanFiles.cmake @ONLY)
diff --git a/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt b/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt
new file mode 100644
index 000000000..55893ae06
--- /dev/null
+++ b/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.14)
+
+# Subdirectory CMakeLists.txt without targets
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+# Register a file path relative to the build directory
+set(DirPropFileRel "DirPropFileRel.txt")
+writeCleanFile("${CBD}/${DirPropFileRel}")
+set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${DirPropFileRel})
+addCleanFile("${CBD}/${DirPropFileRel}")
+
+# Register an absolute file path
+set(DirPropFileAbs "${CBD}/DirPropFileAbs.txt")
+writeCleanFile("${DirPropFileAbs}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropFileAbs})
+addCleanFile("${DirPropFileAbs}")
diff --git a/Tests/MakeClean/check_clean.c.in b/Tests/MakeClean/check_clean.c.in
index 5bc4ab880..e5a7945af 100644
--- a/Tests/MakeClean/check_clean.c.in
+++ b/Tests/MakeClean/check_clean.c.in
@@ -18,7 +18,7 @@ int main()
if(pf)
{
fclose(pf);
- fprintf(stderr, "File \"%s\" exists!", *f);
+ fprintf(stderr, "File \"%s\" still exists!\n", *f);
result = 1;
}
}
diff --git a/Tests/Module/FindDependency/CMakeLists.txt b/Tests/Module/FindDependency/CMakeLists.txt
index dcb998a4b..06d7dce9a 100644
--- a/Tests/Module/FindDependency/CMakeLists.txt
+++ b/Tests/Module/FindDependency/CMakeLists.txt
@@ -6,6 +6,8 @@ set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/packages")
find_package(Pack1 REQUIRED)
find_package(Pack4 4.3 EXACT REQUIRED)
+find_package(Pack7 REQUIRED)
+find_package(Pack8 REQUIRED)
add_executable(FindDependency main.cpp)
-target_link_libraries(FindDependency Pack1::Lib Pack4::Lib)
+target_link_libraries(FindDependency Pack1::Lib Pack4::Lib Pack8::Lib)
diff --git a/Tests/Module/FindDependency/main.cpp b/Tests/Module/FindDependency/main.cpp
index 1df4cb55e..4ee460fbf 100644
--- a/Tests/Module/FindDependency/main.cpp
+++ b/Tests/Module/FindDependency/main.cpp
@@ -23,6 +23,18 @@
# error Expected HAVE_PACK6
#endif
+#ifndef HAVE_PACK7
+# error Expected HAVE_PACK7
+#endif
+
+#ifndef HAVE_PACK7_COMP1
+# error Expected HAVE_PACK7_COMP1
+#endif
+
+#ifndef HAVE_PACK8
+# error Expected HAVE_PACK8
+#endif
+
int main(int argc, char** argv)
{
return 0;
diff --git a/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
new file mode 100644
index 000000000..9df13457f
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
@@ -0,0 +1,14 @@
+if(NOT Pack7_FOUND)
+ set(Pack7_FOUND 1)
+ add_library(Pack7::Pack7 INTERFACE IMPORTED)
+ set_property(TARGET Pack7::Pack7 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7)
+endif()
+
+foreach(module ${Pack7_FIND_COMPONENTS})
+ if(module STREQUAL "Comp1")
+ add_library(Pack7::Comp1 INTERFACE IMPORTED)
+ set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7_COMP1)
+ set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Pack7)
+ set(Pack7_Comp1_FOUND 1)
+ endif()
+endforeach()
diff --git a/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
new file mode 100644
index 000000000..d7ca054e7
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
@@ -0,0 +1,7 @@
+include(CMakeFindDependencyMacro)
+
+find_dependency(Pack7 REQUIRED COMPONENTS Comp1)
+
+add_library(Pack8::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK8)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Comp1)
diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
index 45bb2290b..b30928d78 100644
--- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
+++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
@@ -52,8 +52,10 @@ endmacro()
# detailed features tables, not just meta-features
if (CMAKE_C_COMPILE_FEATURES)
- set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
- list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+ if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+ set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
+ list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+ endif()
endif()
if (C_expected_features)
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" COMPILER_VERSION_MAJOR "${CMAKE_C_COMPILER_VERSION}")
@@ -61,7 +63,7 @@ if (C_expected_features)
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_C_COMPILER_VERSION}")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
- OR CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
OR CMAKE_C_COMPILER_ID STREQUAL "Intel")
add_executable(WriteCompilerDetectionHeader_C11 main.c)
@@ -93,8 +95,10 @@ if (C_expected_features)
endif()
if (CMAKE_CXX_COMPILE_FEATURES)
- set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
- list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+ if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+ set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
+ list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+ endif()
endif()
if (NOT CXX_expected_features)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
@@ -118,7 +122,7 @@ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" COMPILER_VERSION_MINO
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_CXX_COMPILER_VERSION}")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
- OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
OR CMAKE_CXX_COMPILER_ID STREQUAL "SunPro"
OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
@@ -128,7 +132,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
endif()
# for msvc the compiler version determines which c++11 features are available.
-if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"
+ AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" ))
if(";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_delegating_constructors;")
list(APPEND true_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
list(APPEND true_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt
index 4bffd1221..7897ab99b 100644
--- a/Tests/ObjectLibrary/CMakeLists.txt
+++ b/Tests/ObjectLibrary/CMakeLists.txt
@@ -62,4 +62,14 @@ add_custom_target(UseABinternalDep COMMAND ${CMAKE_COMMAND} -E touch UseABintern
add_custom_command(TARGET UseABinternal POST_BUILD COMMAND ${CMAKE_COMMAND} -P UseABinternalDep.cmake)
add_dependencies(UseABinternal UseABinternalDep)
+# Test a static library with sources from a different static library
+add_library(UseCstaticObjs STATIC $<TARGET_OBJECTS:Cstatic> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+
+# Test a shared library with sources from a different shared library
+add_library(UseCsharedObjs SHARED $<TARGET_OBJECTS:Cshared> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+
+# Test a shared executable with sources from a different shared library
+add_executable(UseABstaticObjs $<TARGET_OBJECTS:UseABstatic>)
+target_link_libraries(UseABstaticObjs ABstatic)
+
add_subdirectory(ExportLanguages)
diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt
index 227d990af..c4540db1e 100644
--- a/Tests/Plugin/CMakeLists.txt
+++ b/Tests/Plugin/CMakeLists.txt
@@ -5,6 +5,17 @@ project(Plugin)
# We need proper C++98 support from the compiler
set(CMAKE_CXX_STANDARD 98)
+# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
# Test per-target output directory properties.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/plugin)
@@ -15,6 +26,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/static)
set(KWSYS_NAMESPACE kwsys)
set(KWSYS_HEADER_ROOT ${Plugin_BINARY_DIR}/include)
set(KWSYS_USE_DynamicLoader 1)
+set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_UTF8)
add_subdirectory(${Plugin_SOURCE_DIR}/../../Source/kwsys src/kwsys)
# Configure the location of plugins.
@@ -28,12 +40,6 @@ include_directories(
${Plugin_SOURCE_DIR}/include
)
-# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
-if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
- CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
- set(CMAKE_CXX_STANDARD 11)
-endif()
-
# Create an executable that exports an API for use by plugins.
add_executable(example_exe src/example_exe.cxx)
set_target_properties(example_exe PROPERTIES
diff --git a/Tests/Preprocess/CMakeLists.txt b/Tests/Preprocess/CMakeLists.txt
index 8c2cdc9e7..588af0320 100644
--- a/Tests/Preprocess/CMakeLists.txt
+++ b/Tests/Preprocess/CMakeLists.txt
@@ -28,6 +28,11 @@ endif()
if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
set(PP_VS 1)
endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND
+ "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" AND
+ "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ set(CLANG_GNULIKE_WINDOWS 1)
+endif()
# Some tests below check the PP_* variables set above. They are meant
# to test the case that the build tool is at fault. Other tests below
@@ -53,7 +58,7 @@ endif()
string(APPEND STRING_EXTRA " ")
-if(NOT PP_BORLAND AND NOT PP_WATCOM)
+if(NOT PP_BORLAND AND NOT PP_WATCOM AND NOT CLANG_GNULIKE_WINDOWS)
# Borland, WMake: multiple spaces
# The make tool seems to remove extra whitespace from inside
# quoted strings when passing to the compiler. It does not have
@@ -70,14 +75,14 @@ if(NOT PP_VS)
string(APPEND STRING_EXTRA ",")
endif()
-if(NOT PP_MINGW)
+if(NOT PP_MINGW AND NOT CLANG_GNULIKE_WINDOWS)
# MinGW: &
# When inside -D"FOO=\"a & b\"" MinGW make wants -D"FOO=\"a "&" b\""
# but it does not like quoted ampersand elsewhere.
string(APPEND STRING_EXTRA "&")
endif()
-if(NOT PP_MINGW)
+if(NOT PP_MINGW AND NOT CLANG_GNULIKE_WINDOWS)
# MinGW: |
# When inside -D"FOO=\"a | b\"" MinGW make wants -D"FOO=\"a "|" b\""
# but it does not like quoted pipe elsewhere.
@@ -100,7 +105,8 @@ endif()
set(EXPR_OP1 "/")
if((NOT MSVC OR PP_NMAKE) AND
- NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ NOT CMAKE_C_COMPILER_ID STREQUAL "Intel" AND
+ NOT CLANG_GNULIKE_WINDOWS)
# MSVC cl, Intel icl: %
# When the cl compiler is invoked from the command line then % must
# be written %% (to distinguish from %ENV% syntax). However cl does
diff --git a/Tests/Preprocess/preprocess.c b/Tests/Preprocess/preprocess.c
index 2913f937a..958c77ebc 100644
--- a/Tests/Preprocess/preprocess.c
+++ b/Tests/Preprocess/preprocess.c
@@ -10,7 +10,8 @@ int check_defines_C(void)
{
int result = 1;
if (strcmp(FILE_STRING, STRING_VALUE) != 0) {
- fprintf(stderr, "FILE_STRING has wrong value in C [%s]\n", FILE_STRING);
+ fprintf(stderr, "FILE_STRING has wrong value in C [%s] vs [%s]\n",
+ FILE_STRING, STRING_VALUE);
result = 0;
}
if (strcmp(TARGET_STRING, STRING_VALUE) != 0) {
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
index cff7022d2..81fd8db27 100644
--- a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
+++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
@@ -69,6 +69,9 @@ file(MAKE_DIRECTORY ${GAT_BDIR})
message("___ Configuring GAT project ___")
execute_process(
COMMAND "${CMAKE_COMMAND}" "${GAT_SDIR}"
+ -G "${CMAKE_GENERATOR}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
"-DQT_TEST_VERSION=${QT_TEST_VERSION}"
"-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
"-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
diff --git a/Tests/QtAutogen/ManySources/CMakeLists.txt b/Tests/QtAutogen/ManySources/CMakeLists.txt
new file mode 100644
index 000000000..df8a2a662
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.10)
+project(ManySources)
+include("../AutogenGuiTest.cmake")
+
+# Test AUTOMOC and AUTOUIC on many source files to stress the concurrent
+# parsing and processing framework.
+
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SRCS main.cpp)
+set(MAIN_INCLUDES "\n// Item includes\n")
+set(MAIN_ITEMS "\n// Items\n")
+
+set(NUM 24)
+foreach(III RANGE 1 ${NUM})
+ configure_file(${CSD}/object.h.in ${CBD}/object_${III}.h)
+ configure_file(${CSD}/item.h.in ${CBD}/item_${III}.h)
+ configure_file(${CSD}/item.cpp.in ${CBD}/item_${III}.cpp)
+ configure_file(${CSD}/view.ui.in ${CBD}/view_${III}.ui)
+ configure_file(${CSD}/data.qrc.in ${CBD}/data_${III}.qrc)
+
+ list(APPEND SRCS ${CBD}/item_${III}.cpp)
+ list(APPEND SRCS ${CBD}/data_${III}.qrc)
+
+ string(APPEND MAIN_INCLUDES "#include \"item_${III}.h\"\n")
+ string(APPEND MAIN_ITEMS "Item_${III} item_${III};\n")
+ string(APPEND MAIN_ITEMS "item_${III}.TheSlot();\n")
+endforeach()
+
+configure_file(${CSD}/main.cpp.in ${CBD}/main.cpp)
+
+add_executable(manySources ${SRCS} ${CBD}/main.cpp)
+target_link_libraries(manySources ${QT_LIBRARIES})
+set_target_properties(manySources PROPERTIES AUTOMOC 1 AUTOUIC 1 AUTORCC 1)
diff --git a/Tests/QtAutogen/ManySources/data.qrc.in b/Tests/QtAutogen/ManySources/data.qrc.in
new file mode 100644
index 000000000..870d48631
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/data.qrc.in
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>object_@III@.h</file>
+ <file>item_@III@.h</file>
+ <file>item_@III@.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/ManySources/item.cpp.in b/Tests/QtAutogen/ManySources/item.cpp.in
new file mode 100644
index 000000000..c34ad16d0
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/item.cpp.in
@@ -0,0 +1,27 @@
+#include "item_@III@.h"
+#include "object_@III@.h"
+// AUTOUIC include
+#include <ui_view_@III@.h>
+
+class LocalObject_@III@ : public QObject
+{
+ Q_OBJECT;
+
+public:
+ LocalObject_@III@() = default;
+ ~LocalObject_@III@() = default;
+};
+
+void Item_@III@ ::TheSlot()
+{
+ LocalObject_@III@ localObject;
+ Object_@III@ obj;
+ obj.ObjectSlot();
+
+ Ui_View_@III@ ui_view;
+}
+
+// AUTOMOC includes
+#include "item_@III@.moc"
+#include "moc_item_@III@.cpp"
+#include "moc_object_@III@.cpp"
diff --git a/Tests/QtAutogen/ManySources/item.h.in b/Tests/QtAutogen/ManySources/item.h.in
new file mode 100644
index 000000000..67ad79435
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/item.h.in
@@ -0,0 +1,15 @@
+#ifndef ITEM_@III@HPP
+#define ITEM_@III@HPP
+
+#include <QObject>
+
+class Item_@III@ : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_SLOT
+ void TheSlot();
+};
+
+#endif
diff --git a/Tests/QtAutogen/ManySources/main.cpp.in b/Tests/QtAutogen/ManySources/main.cpp.in
new file mode 100644
index 000000000..e1dda40b7
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/main.cpp.in
@@ -0,0 +1,7 @@
+@MAIN_INCLUDES@
+
+int main(int argv, char** args)
+{
+ @MAIN_ITEMS@
+ return 0;
+}
diff --git a/Tests/QtAutogen/ManySources/object.h.in b/Tests/QtAutogen/ManySources/object.h.in
new file mode 100644
index 000000000..a747cbcfa
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/object.h.in
@@ -0,0 +1,15 @@
+#ifndef OBJECT_@III@H
+#define OBJECT_@III@H
+
+#include <QObject>
+
+class Object_@III@ : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_SLOT
+ void ObjectSlot(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/ManySources/view.ui.in b/Tests/QtAutogen/ManySources/view.ui.in
new file mode 100644
index 000000000..6901fe3de
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/view.ui.in
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View_@III@</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
index f4b726f63..9b32e5951 100644
--- a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
@@ -5,10 +5,48 @@ include("../AutogenCoreTest.cmake")
# Dummy executable to generate a clean target
add_executable(dummy dummy.cpp)
-set(timeformat "%Y%j%H%M%S")
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
set(mocBasicSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocBasic")
set(mocBasicBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocBasic")
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamp When)
+ file(TIMESTAMP "${mocBasicBin}" time${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+macro(require_change)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(STATUS "As expected the file ${mocBasicBin} changed.")
+ else()
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} did not change!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ endif()
+endmacro()
+
+macro(require_change_not)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} changed!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ else()
+ message(STATUS "As expected the file ${mocBasicBin} did not change.")
+ endif()
+endmacro()
+
+
# Initial build
configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
try_compile(MOC_RERUN
@@ -21,46 +59,44 @@ try_compile(MOC_RERUN
OUTPUT_VARIABLE output
)
if (NOT MOC_RERUN)
- message(SEND_ERROR "Initial build of mocBasic failed. Output: ${output}")
+ message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}")
endif()
+
# Get name of the output binary
file(STRINGS "${mocBasicBinDir}/mocBasic.txt" mocBasicList ENCODING UTF-8)
list(GET mocBasicList 0 mocBasicBin)
-message("Changing the header content for a MOC rerun")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${mocBasicBin}" timeBefore "${timeformat}")
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Touching binary file to ensure a new timestamps")
+file(TOUCH_NOCREATE "${mocBasicBin}")
+acquire_timestamp(After)
+require_change()
+
+
# - Ensure that the timestamp will change
-# - Change header file content and rebuild
+# - Change header file content
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing the header content for a MOC re-run")
configure_file("${mocBasicSrcDir}/test1b.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result )
-if (result)
- message(SEND_ERROR "Second build of mocBasic failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${mocBasicBin}" timeAfter "${timeformat}")
-# - Test if timestamps changed
-if (NOT timeAfter GREATER timeBefore)
- message(SEND_ERROR "File (${mocBasicBin}) should have changed!")
-endif()
+sleep()
+rebuild(2)
+acquire_timestamp(After)
+require_change()
-message("Changing nothing for a MOC rerun")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${mocBasicBin}" timeBefore "${timeformat}")
# - Ensure that the timestamp would change
# - Change nothing
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result )
-if (result)
- message(SEND_ERROR "Third build of mocBasic failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${mocBasicBin}" timeAfter "${timeformat}")
-# - Test if timestamps changed
-if (timeAfter GREATER timeBefore)
- message(SEND_ERROR "File (${mocBasicBin}) should not have changed!")
-endif()
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing nothing for no MOC re-run")
+rebuild(3)
+acquire_timestamp(After)
+require_change_not()
diff --git a/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
index b83e99419..e1951f1d0 100644
--- a/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
@@ -9,10 +9,53 @@ include("../AutogenCoreTest.cmake")
add_executable(dummy dummy.cpp)
# Utility variables
-set(timeformat "%Y%j%H%M%S")
+set(timeformat "%Y.%j.%H.%M%S")
set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocPlugin")
set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocPlugin")
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}" RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+macro(require_change PLG)
+ if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+ message(STATUS "As expected the file ${pl${PLG}File} changed.")
+ else()
+ message(SEND_ERROR
+ "Unexpectedly the file ${pl${PLG}File} did not change!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+ endif()
+endmacro()
+
+macro(require_change_not PLG)
+ if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+ message(SEND_ERROR
+ "Unexpectedly the file ${pl${PLG}File} changed!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+ else()
+ message(STATUS "As expected the file ${pl${PLG}File} did not change.")
+ endif()
+endmacro()
+
+macro(acquire_timestamps When)
+ file(TIMESTAMP "${plAFile}" plA${When} "${timeformat}")
+ file(TIMESTAMP "${plBFile}" plB${When} "${timeformat}")
+ file(TIMESTAMP "${plCFile}" plC${When} "${timeformat}")
+ file(TIMESTAMP "${plDFile}" plD${When} "${timeformat}")
+ file(TIMESTAMP "${plEFile}" plE${When} "${timeformat}")
+endmacro()
+
+
# Initial build
try_compile(MOC_PLUGIN
"${mocPlugBinDir}"
@@ -24,83 +67,68 @@ try_compile(MOC_PLUGIN
OUTPUT_VARIABLE output
)
if (NOT MOC_PLUGIN)
- message(SEND_ERROR "Initial build of mocPlugin failed. Output: ${output}")
+ message(FATAL_ERROR "Initial build of mocPlugin failed. Output: ${output}")
endif()
+# Get names of the output binaries
find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+# To avoid a race condition where the library has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - rebuild library to ensure it has a new timestamp
+sleep()
+message(STATUS "Rebuilding library files to ensure new timestamps")
+rebuild(1)
+
+
# - Ensure that the timestamp will change.
# - Change the json files referenced by Q_PLUGIN_METADATA
# - Rebuild
-file(TIMESTAMP "${plAFile}" plABefore "${timeformat}")
-file(TIMESTAMP "${plBFile}" plBBefore "${timeformat}")
-file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}")
-
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files.")
configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json")
configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json")
configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}")
-
-file(TIMESTAMP "${plAFile}" plAAfter "${timeformat}")
-file(TIMESTAMP "${plBFile}" plBAfter "${timeformat}")
-file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}")
-
-if (plAAfter GREATER plABefore)
- message(SEND_ERROR "file (${plAFile}) should not have changed!")
-endif()
-if (plBAfter GREATER plBBefore)
- message(SEND_ERROR "file (${plBFile}) should not have changed!")
-endif()
-if (NOT plCAfter GREATER plCBefore)
- message(SEND_ERROR "file (${plCFile}) should have changed!")
-endif()
-if (NOT plDAfter GREATER plDBefore)
- message(SEND_ERROR "file (${plDFile}) should have changed!")
-endif()
-if (NOT plEAfter GREATER plEBefore)
- # There's a bug in Ninja on Windows
- # https://gitlab.kitware.com/cmake/cmake/issues/16776
- if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
- message(SEND_ERROR "file (${plEFile}) should have changed!")
- endif()
+sleep()
+rebuild(2)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows:
+# https://gitlab.kitware.com/cmake/cmake/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+ require_change(E)
endif()
+
# - Ensure that the timestamp will change.
# - Change the json files referenced by A_CUSTOM_MACRO
# - Rebuild
-file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}")
-
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files")
configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json")
configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json")
configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}")
-
-file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}")
-
-if (NOT plCAfter GREATER plCBefore)
- message(SEND_ERROR "file (${plCFile}) should have changed!")
-endif()
-if (NOT plDAfter GREATER plDBefore)
- message(SEND_ERROR "file (${plDFile}) should have changed!")
-endif()
-if (NOT plEAfter GREATER plEBefore)
- # There's a bug in Ninja on Windows
- # https://gitlab.kitware.com/cmake/cmake/issues/16776
- if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
- message(SEND_ERROR "file (${plEFile}) should have changed!")
- endif()
+sleep()
+rebuild(3)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows
+# https://gitlab.kitware.com/cmake/cmake/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+ require_change(E)
endif()
diff --git a/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
index dcb7a79ce..33c01acbe 100644
--- a/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
@@ -9,10 +9,23 @@ add_executable(dummy dummy.cpp)
# When a .qrc or a file listed in a .qrc file changes,
# the target must be rebuilt
-set(timeformat "%Y%j%H%M%S")
set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccConfigChange")
set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccConfigChange")
+# Rebuild macro
+macro(rebuild CFG)
+ message(STATUS "Rebuilding rccConfigChange in ${CFG} configuration.")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build . --config "${CFG}"
+ WORKING_DIRECTORY "${rccDepBD}"
+ RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "${CFG} build of rccConfigChange failed.")
+ else()
+ message(STATUS "${CFG} build of rccConfigChange finished.")
+ endif()
+endmacro()
+
# Initial build
try_compile(RCC_DEPENDS
"${rccDepBD}"
@@ -24,19 +37,11 @@ try_compile(RCC_DEPENDS
OUTPUT_VARIABLE output
)
if (NOT RCC_DEPENDS)
- message(SEND_ERROR "Initial build of rccConfigChange failed. Output: ${output}")
+ message(FATAL_ERROR "Initial build of rccConfigChange failed. Output: ${output}")
endif()
-# - Rebuild Release
-message("Rebuilding rccConfigChange in Release configuration")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config Release WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Release build of rccConfigChange failed.")
-endif()
+# Rebuild: Release
+rebuild(Release)
-# - Rebuild Debug
-message("Rebuilding rccConfigChange in Debug configuration")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config Debug WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Debug build of rccConfigChange failed.")
-endif()
+# Rebuild: Debug
+rebuild(Debug)
diff --git a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
index 80c5cf035..1301550f2 100644
--- a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
@@ -3,19 +3,63 @@ project(RerunRccDepends)
include("../AutogenCoreTest.cmake")
# Tests rcc rebuilding when a resource file changes
+# When a .qrc or a file listed in a .qrc file changes,
+# the target must be rebuilt
# Dummy executable to generate a clean target
add_executable(dummy dummy.cpp)
-# When a .qrc or a file listed in a .qrc file changes,
-# the target must be rebuilt
-set(timeformat "%Y%j%H%M%S")
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccDepends")
set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccDepends")
-# Initial build
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamps When)
+ file(TIMESTAMP "${rccDepBinPlain}" rdPlain${When} "${timeformat}")
+ file(TIMESTAMP "${rccDepBinGenerated}" rdGenerated${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName} of rccDepends.")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build .
+ WORKING_DIRECTORY "${rccDepBD}"
+ RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} of rccDepends failed.")
+ else()
+ message(STATUS "Build ${buildName} of rccDepends finished.")
+ endif()
+endmacro()
+
+macro(require_change type)
+ if (rd${type}After VERSION_GREATER rd${type}Before)
+ message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} changed.")
+ else()
+ message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} did not change!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+ endif()
+endmacro()
+
+macro(require_change_not type)
+ if (rd${type}After VERSION_GREATER rd${type}Before)
+ message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} changed!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+ else()
+ message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} did not change.")
+ endif()
+endmacro()
+
+
+# Initial configuration
configure_file(${rccDepSD}/resPlainA.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
configure_file(${rccDepSD}/resGenA.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
+
+# Initial build
try_compile(RCC_DEPENDS
"${rccDepBD}"
"${rccDepSD}"
@@ -26,113 +70,84 @@ try_compile(RCC_DEPENDS
OUTPUT_VARIABLE output
)
if (NOT RCC_DEPENDS)
- message(SEND_ERROR "Initial build of rccDepends failed. Output: ${output}")
+ message(FATAL_ERROR "Initial build of rccDepends failed. Output: ${output}")
endif()
# Get name of the output binaries
file(STRINGS "${rccDepBD}/targetPlain.txt" targetListPlain ENCODING UTF-8)
file(STRINGS "${rccDepBD}/targetGen.txt" targetListGen ENCODING UTF-8)
list(GET targetListPlain 0 rccDepBinPlain)
-list(GET targetListGen 0 rccDepBinGen)
-message("Target that uses a plain .qrc file is:\n ${rccDepBinPlain}")
-message("Target that uses a GENERATED .qrc file is:\n ${rccDepBinGen}")
+list(GET targetListGen 0 rccDepBinGenerated)
+message(STATUS "Target that uses a plain .qrc file is:\n ${rccDepBinPlain}")
+message(STATUS "Target that uses a GENERATED .qrc file is:\n ${rccDepBinGenerated}")
+
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Touching binary files to ensure new timestamps")
+file(TOUCH_NOCREATE "${rccDepBinPlain}" "${rccDepBinGenerated}")
+acquire_timestamps(After)
+require_change(Plain)
+require_change(Generated)
-message("Changing a resource files listed in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
# - Ensure that the timestamp will change
# - Change a resource files listed in the .qrc file
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a resource file listed in the .qrc file")
file(TOUCH "${rccDepBD}/resPlain/input.txt" "${rccDepBD}/resGen/input.txt")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Second build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(2)
+acquire_timestamps(After)
# - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
- message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
- message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
-message("Changing the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
# - Ensure that the timestamp will change
# - Change the .qrc file
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing the .qrc file")
configure_file(${rccDepSD}/resPlainB.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
configure_file(${rccDepSD}/resGenB.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Third build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(3)
+acquire_timestamps(After)
# - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
- message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
- message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
-message("Changing a newly added resource files listed in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
# - Ensure that the timestamp will change
# - Change a newly added resource files listed in the .qrc file
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a newly added resource file listed in the .qrc file")
file(TOUCH "${rccDepBD}/resPlain/inputAdded.txt" "${rccDepBD}/resGen/inputAdded.txt")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Fourth build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(4)
+acquire_timestamps(After)
# - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
- message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
- message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
-message("Changing nothing in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
# - Ensure that the timestamp will change
# - Change nothing
# - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
- message(SEND_ERROR "Fifth build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing nothing in the .qrc file")
+rebuild(5)
+acquire_timestamps(After)
# - Test if timestamps changed
-if (rdPlainAfter GREATER rdPlainBefore)
- message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should NOT have changed!")
-endif()
-if (rdGenAfter GREATER rdGenBefore)
- message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should NOT have changed!")
-endif()
+require_change_not(Plain)
+require_change_not(Generated)
diff --git a/Tests/QtAutogen/SameName/CMakeLists.txt b/Tests/QtAutogen/SameName/CMakeLists.txt
index 8d4f71f65..0a80d5eee 100644
--- a/Tests/QtAutogen/SameName/CMakeLists.txt
+++ b/Tests/QtAutogen/SameName/CMakeLists.txt
@@ -37,7 +37,7 @@ if (QT_TEST_VERSION EQUAL 4)
else()
set(rccCompress "--compress")
endif()
-set_target_properties(sameName PROPERTIES AUTORCC_OPTIONS "${rccCompress};0" )
-set_source_files_properties(aaa/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};1" )
-set_source_files_properties(bbb/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};2" )
-set_source_files_properties(ccc/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};3" )
+set_target_properties(sameName PROPERTIES AUTORCC_OPTIONS "${rccCompress};1" )
+set_source_files_properties(aaa/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};2" )
+set_source_files_properties(bbb/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};3" )
+set_source_files_properties(ccc/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};4" )
diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake
index 096d5e3bd..6771828e6 100644
--- a/Tests/QtAutogen/Tests.cmake
+++ b/Tests/QtAutogen/Tests.cmake
@@ -5,6 +5,7 @@ ADD_AUTOGEN_TEST(AutogenTargetDepends)
ADD_AUTOGEN_TEST(Complex QtAutogen)
ADD_AUTOGEN_TEST(GlobalAutogenTarget)
ADD_AUTOGEN_TEST(LowMinimumVersion lowMinimumVersion)
+ADD_AUTOGEN_TEST(ManySources manySources)
ADD_AUTOGEN_TEST(MocOnly mocOnly)
ADD_AUTOGEN_TEST(MocOptions mocOptions)
ADD_AUTOGEN_TEST(ObjectLibrary someProgram)
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt
index ddb3cae61..87ac88e62 100644
--- a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at CMP0069-NEW-cmake\.cmake:[0-9]+ \(add_executable\):
CMake doesn't support IPO for current compiler
Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt
index 8decfab3c..cb9d19b47 100644
--- a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at CMP0069-NEW-compiler\.cmake:[0-9]+ \(add_executable\):
Compiler doesn't support IPO
Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt
index 0e05ee783..1159ec043 100644
--- a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at CMP0069-NEW-generator\.cmake:[0-9]+ \(add_executable\):
CMake doesn't support IPO for current generator
Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index f2b7ff192..69f816215 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -192,13 +192,20 @@ add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
add_RunCMake_test(TargetPropertyGeneratorExpressions)
add_RunCMake_test(Languages)
add_RunCMake_test(LinkStatic)
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+ add_RunCMake_test(MetaCompileFeatures)
+endif()
+if(MSVC)
+ add_RunCMake_test(MSVCRuntimeLibrary)
+ add_RunCMake_test(MSVCWarningFlags)
+endif()
add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(ParseImplicitIncludeInfo)
if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
add_RunCMake_test(RuntimePath)
endif()
add_RunCMake_test(ScriptMode)
-add_RunCMake_test(Swift)
+add_RunCMake_test(Swift -DCMAKE_Swift_COMPILER=${CMAKE_Swift_COMPILER})
add_RunCMake_test(TargetObjects)
add_RunCMake_test(TargetSources)
add_RunCMake_test(ToolchainFile)
@@ -252,6 +259,7 @@ add_RunCMake_test(ctest_submit)
add_RunCMake_test(ctest_test)
add_RunCMake_test(ctest_disabled_test)
add_RunCMake_test(ctest_skipped_test)
+add_RunCMake_test(ctest_update)
add_RunCMake_test(ctest_upload)
add_RunCMake_test(ctest_fixtures)
add_RunCMake_test(file)
@@ -339,8 +347,7 @@ if(PKG_CONFIG_FOUND)
add_RunCMake_test(FindPkgConfig)
endif()
-find_package(GTK2 QUIET)
-if (GTK2_FOUND)
+if(CMake_TEST_FindGTK2)
add_RunCMake_test(FindGTK2)
endif()
@@ -353,7 +360,10 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
endif()
if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
- add_RunCMake_test(VS10Project)
+ add_RunCMake_test(VS10Project
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
+ )
if( vs12 AND wince )
add_RunCMake_test( VS10ProjectWinCE "-DRunCMake_GENERATOR_PLATFORM=${wince_sdk}")
endif()
@@ -438,9 +448,11 @@ endif()
add_executable(pseudo_emulator pseudo_emulator.c)
add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c)
+add_executable(pseudo_emulator_custom_command_arg pseudo_emulator_custom_command_arg.c)
add_RunCMake_test(CrosscompilingEmulator
-DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
- -DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>)
+ -DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>
+ -DPSEUDO_EMULATOR_CUSTOM_COMMAND_ARG=$<TARGET_FILE:pseudo_emulator_custom_command_arg>)
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
if(UNIX AND NOT CYGWIN)
execute_process(COMMAND ldd --help
diff --git a/Tests/RunCMake/CTestCommandLine/show_only_json_check.pyc b/Tests/RunCMake/CTestCommandLine/show_only_json_check.pyc
index a4c9959c9..bd23f0ad4 100644
--- a/Tests/RunCMake/CTestCommandLine/show_only_json_check.pyc
+++ b/Tests/RunCMake/CTestCommandLine/show_only_json_check.pyc
Binary files differ
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt
index d00491fd7..d00491fd7 100644
--- a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt
index f2cbaa622..94fc15732 100644
--- a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt
@@ -1,3 +1,3 @@
-^'--target' may not be specified more than once\.
+^The <jobs> value is too large\.
+
Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt
index d00491fd7..d00491fd7 100644
--- a/Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-result.txt
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt
new file mode 100644
index 000000000..8ed4fee99
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt
@@ -0,0 +1,3 @@
+^The <jobs> value requires a positive integer argument\.
++
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt
new file mode 100644
index 000000000..94fc15732
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt
@@ -0,0 +1,3 @@
+^The <jobs> value is too large\.
++
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt
new file mode 100644
index 000000000..8ed4fee99
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt
@@ -0,0 +1,3 @@
+^The <jobs> value requires a positive integer argument\.
++
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt
new file mode 100644
index 000000000..3c2c808e9
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt
new file mode 100644
index 000000000..40d9bec84
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt
@@ -0,0 +1,2 @@
+^Error: Building 'clean' and other targets together is not supported\.
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt
new file mode 100644
index 000000000..40d9bec84
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt
@@ -0,0 +1,2 @@
+^Error: Building 'clean' and other targets together is not supported\.
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index 6c5ea44b3..b4b170ef2 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{.*}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":true,"version":{.*}}$
diff --git a/Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-check.cmake b/Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-check.cmake
new file mode 100644
index 000000000..ea3d161af
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-check.cmake
@@ -0,0 +1,3 @@
+if(NOT IS_DIRECTORY ${out}/parent/child)
+ set(RunCMake_TEST_FAILED "child directory was not created")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_make_directory-three-directories-check.cmake b/Tests/RunCMake/CommandLine/E_make_directory-three-directories-check.cmake
new file mode 100644
index 000000000..c1e84744a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_make_directory-three-directories-check.cmake
@@ -0,0 +1,6 @@
+if(NOT IS_DIRECTORY ${out}/d1)
+ set(RunCMake_TEST_FAILED "directory d1 was not created")
+endif()
+if(NOT IS_DIRECTORY ${out}/d2)
+ set(RunCMake_TEST_FAILED "directory d2 was not created")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-result.txt b/Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-stderr.txt b/Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-stderr.txt
index 08a9428f4..08a9428f4 100644
--- a/Tests/RunCMake/CommandLine/E_make_directory-three-directories-and-file-stderr.txt
+++ b/Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-stderr.txt
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-check.cmake b/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-check.cmake
new file mode 100644
index 000000000..fd6ea111f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-check.cmake
@@ -0,0 +1,3 @@
+if(IS_DIRECTORY ${out}/parent/child)
+ set(RunCMake_TEST_FAILED "child directory was not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-stderr.txt b/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-stderr.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-stderr.txt
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-check.cmake b/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-check.cmake
new file mode 100644
index 000000000..2b7202ad5
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-check.cmake
@@ -0,0 +1,6 @@
+if(IS_DIRECTORY ${out}/d1)
+ set(RunCMake_TEST_FAILED "directory d1 was not removed")
+endif()
+if(IS_DIRECTORY ${out}/d2)
+ set(RunCMake_TEST_FAILED "directory d2 was not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-stderr.txt b/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-stderr.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-three-directories-stderr.txt
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-check.cmake b/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-check.cmake
new file mode 100644
index 000000000..0aa4a5202
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${outfile})
+ set(RunCMake_TEST_FAILED "removed non-directory ${outfile}")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-stderr.txt b/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-stderr.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-stderr.txt
diff --git a/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt b/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt
new file mode 100644
index 000000000..2b8c65c9b
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.14)
+project(EnvGenerator C)
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ message(STATUS "CMAKE_VS_PLATFORM_NAME='${CMAKE_VS_PLATFORM_NAME}'")
+endif()
+add_custom_command(
+ OUTPUT output.txt
+ COMMAND ${CMAKE_COMMAND} -E echo CustomCommand > output.txt
+ )
+add_custom_target(CustomTarget ALL DEPENDS output.txt)
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt
new file mode 100644
index 000000000..4eae6aa10
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+ No CMAKE_C_COMPILER could be found.
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt
new file mode 100644
index 000000000..09c2d2ba1
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+Platform='fromcli'.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt
new file mode 100644
index 000000000..4dd6be1da
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt
@@ -0,0 +1 @@
+-- CMAKE_VS_PLATFORM_NAME='(x64|Win32)'
diff --git a/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt b/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt
new file mode 100644
index 000000000..b432c19d1
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+(Platform Toolset = 'fromcli'|Specified platform toolset \(fromcli\) is not installed or invalid).+
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-result.txt b/Tests/RunCMake/CommandLine/Envgen-bad-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt
new file mode 100644
index 000000000..4a1215eb2
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: No generator specified for -G
+CMake Error: CMAKE_GENERATOR was set but the specified generator doesn't exist. Using CMake default.
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt
new file mode 100644
index 000000000..d53daa5a2
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+ could not find specified instance of Visual Studio.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt
new file mode 100644
index 000000000..0d455db74
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error: No generator specified for -G
+
+Generators.*
+\* Ninja.*
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt
new file mode 100644
index 000000000..4eae6aa10
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+ No CMAKE_C_COMPILER could be found.
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt
new file mode 100644
index 000000000..76a8f1cac
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+Platform='invalid'.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt
new file mode 100644
index 000000000..51fce609d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+(Platform Toolset = 'invalid'|Specified platform toolset \(invalid\) is not installed or invalid).+
diff --git a/Tests/RunCMake/CommandLine/Envgen-unset-result.txt b/Tests/RunCMake/CommandLine/Envgen-unset-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-unset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt
new file mode 100644
index 000000000..ec6ec9253
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error: No generator specified for -G
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt b/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt
new file mode 100644
index 000000000..47f9c9e0a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt
@@ -0,0 +1,7 @@
+^Warning: Environment variable CMAKE_GENERATOR_INSTANCE will be ignored, because CMAKE_GENERATOR is not set.
+Warning: Environment variable CMAKE_GENERATOR_PLATFORM will be ignored, because CMAKE_GENERATOR is not set.
+Warning: Environment variable CMAKE_GENERATOR_TOOLSET will be ignored, because CMAKE_GENERATOR is not set.
+CMake Error: No generator specified for -G
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
index 0ca5a0a0b..fc6291445 100644
--- a/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
+++ b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
@@ -1,4 +1,5 @@
-cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.14)
+project(ExplicitDirs NONE)
add_custom_command(
OUTPUT output.txt
COMMAND ${CMAKE_COMMAND} -E echo CustomCommand > output.txt
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 23fb9ef46..c9d3a4ddd 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -54,12 +54,23 @@ run_cmake_command(build-bad-dir
run_cmake_command(build-bad-generator
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-generator)
+run_cmake_command(install-no-dir
+ ${CMAKE_COMMAND} --install)
+run_cmake_command(install-bad-dir
+ ${CMAKE_COMMAND} --install dir-does-not-exist)
+run_cmake_command(install-options-to-vars
+ ${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
+ --strip --prefix /var/test --config sample --component pack)
+
run_cmake_command(cache-bad-entry
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-entry/)
run_cmake_command(cache-empty-entry
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-empty-entry/)
function(run_ExplicitDirs)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(RunCMake_TEST_NO_SOURCE_DIR 1)
+
set(source_dir ${RunCMake_BINARY_DIR}/ExplicitDirsMissing)
file(REMOVE_RECURSE "${source_dir}")
@@ -68,29 +79,32 @@ function(run_ExplicitDirs)
cmake_minimum_required(VERSION 3.13)
project(ExplicitDirsMissing LANGUAGES NONE)
]=])
- run_cmake_command(no-S-B ${CMAKE_COMMAND} -E chdir ${source_dir}
- ${CMAKE_COMMAND} -DFOO=BAR)
+ set(RunCMake_TEST_SOURCE_DIR "${source_dir}")
+ set(RunCMake_TEST_BINARY_DIR "${source_dir}")
+ run_cmake_with_options(no-S-B -DFOO=BAR)
set(source_dir ${RunCMake_SOURCE_DIR}/ExplicitDirs)
set(binary_dir ${RunCMake_BINARY_DIR}/ExplicitDirs-build)
+ set(RunCMake_TEST_SOURCE_DIR "${source_dir}")
+ set(RunCMake_TEST_BINARY_DIR "${binary_dir}")
+
file(REMOVE_RECURSE "${binary_dir}")
- file(MAKE_DIRECTORY "${binary_dir}")
- run_cmake_command(S-arg ${CMAKE_COMMAND} -S ${source_dir} ${binary_dir})
- run_cmake_command(S-arg-reverse-order ${CMAKE_COMMAND} ${binary_dir} -S${source_dir} )
- run_cmake_command(S-no-arg ${CMAKE_COMMAND} -S )
- run_cmake_command(S-no-arg2 ${CMAKE_COMMAND} -S -T)
- run_cmake_command(S-B ${CMAKE_COMMAND} -S ${source_dir} -B ${binary_dir})
+ run_cmake_with_options(S-arg -S ${source_dir} ${binary_dir})
+ run_cmake_with_options(S-arg-reverse-order ${binary_dir} -S${source_dir} )
+ run_cmake_with_options(S-no-arg -S )
+ run_cmake_with_options(S-no-arg2 -S -T)
+ run_cmake_with_options(S-B -S ${source_dir} -B ${binary_dir})
# make sure that -B can explicitly construct build directories
file(REMOVE_RECURSE "${binary_dir}")
- run_cmake_command(B-arg ${CMAKE_COMMAND} -B ${binary_dir} ${source_dir})
+ run_cmake_with_options(B-arg -B ${binary_dir} ${source_dir})
file(REMOVE_RECURSE "${binary_dir}")
- run_cmake_command(B-arg-reverse-order ${CMAKE_COMMAND} ${source_dir} -B${binary_dir})
- run_cmake_command(B-no-arg ${CMAKE_COMMAND} -B )
- run_cmake_command(B-no-arg2 ${CMAKE_COMMAND} -B -T)
+ run_cmake_with_options(B-arg-reverse-order ${source_dir} -B${binary_dir})
+ run_cmake_with_options(B-no-arg -B )
+ run_cmake_with_options(B-no-arg2 -B -T)
file(REMOVE_RECURSE "${binary_dir}")
- run_cmake_command(B-S ${CMAKE_COMMAND} -B${binary_dir} -S${source_dir})
+ run_cmake_with_options(B-S -B${binary_dir} -S${source_dir})
endfunction()
run_ExplicitDirs()
@@ -106,7 +120,13 @@ function(run_BuildDir)
run_cmake_command(BuildDir--build ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget)
run_cmake_command(BuildDir--build-multiple-targets ${CMAKE_COMMAND} -E chdir ..
- ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget2 --target CustomTarget3)
+ ${CMAKE_COMMAND} --build BuildDir-build -t CustomTarget2 --target CustomTarget3)
+ run_cmake_command(BuildDir--build-multiple-targets-jobs ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget CustomTarget2 -j2 --target CustomTarget3)
+ run_cmake_command(BuildDir--build-multiple-targets-with-clean-first ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build --target clean CustomTarget)
+ run_cmake_command(BuildDir--build-multiple-targets-with-clean-second ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget clean)
run_cmake_command(BuildDir--build-jobs-bad-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j 12ab)
run_cmake_command(BuildDir--build-jobs-good-number ${CMAKE_COMMAND} -E chdir ..
@@ -131,6 +151,14 @@ function(run_BuildDir)
${CMAKE_COMMAND} --build BuildDir-build --parallel2)
run_cmake_command(BuildDir--build--parallel-no-space-good-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel2 --target CustomTarget)
+ run_cmake_command(BuildDir--build-jobs-zero ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build -j 0)
+ run_cmake_command(BuildDir--build--parallel-zero ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build --parallel 0)
+ run_cmake_command(BuildDir--build-jobs-large ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build BuildDir-build -j 4294967293)
+ 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")
@@ -146,6 +174,74 @@ function(run_BuildDir)
endfunction()
run_BuildDir()
+function(run_EnvironmentGenerator)
+ set(source_dir ${RunCMake_SOURCE_DIR}/EnvGenerator)
+
+ set(ENV{CMAKE_GENERATOR_INSTANCE} "instance")
+ set(ENV{CMAKE_GENERATOR_PLATFORM} "platform")
+ set(ENV{CMAKE_GENERATOR_TOOLSET} "toolset")
+ run_cmake_command(Envgen-warnings ${CMAKE_COMMAND} -G)
+ unset(ENV{CMAKE_GENERATOR_INSTANCE})
+ unset(ENV{CMAKE_GENERATOR_PLATFORM})
+ unset(ENV{CMAKE_GENERATOR_TOOLSET})
+
+ # Test CMAKE_GENERATOR without actual configuring
+ run_cmake_command(Envgen-unset ${CMAKE_COMMAND} -G)
+ set(ENV{CMAKE_GENERATOR} "Ninja")
+ run_cmake_command(Envgen-ninja ${CMAKE_COMMAND} -G)
+ set(ENV{CMAKE_GENERATOR} "NoSuchGenerator")
+ run_cmake_command(Envgen-bad ${CMAKE_COMMAND} -G)
+ unset(ENV{CMAKE_GENERATOR})
+
+ if(RunCMake_GENERATOR MATCHES "Visual Studio.*")
+ set(ENV{CMAKE_GENERATOR} "${RunCMake_GENERATOR}")
+ run_cmake_command(Envgen ${CMAKE_COMMAND} ${source_dir})
+ # Toolset is available since VS 2010.
+ if(RunCMake_GENERATOR MATCHES "Visual Studio [1-9][0-9]")
+ set(ENV{CMAKE_GENERATOR_TOOLSET} "invalid")
+ # Envvar shouldn't affect existing build tree
+ run_cmake_command(Envgen-toolset-existing ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build Envgen-build)
+ run_cmake_command(Envgen-toolset-invalid ${CMAKE_COMMAND} ${source_dir})
+ # Command line -G implies -T""
+ run_cmake_command(Envgen-G-implicit-toolset ${CMAKE_COMMAND} -G "${RunCMake_GENERATOR}" ${source_dir})
+ run_cmake_command(Envgen-T-toolset ${CMAKE_COMMAND} -T "fromcli" ${source_dir})
+ unset(ENV{CMAKE_GENERATOR_TOOLSET})
+ endif()
+ # Platform can be set only if not in generator name.
+ if(RunCMake_GENERATOR MATCHES "^Visual Studio [0-9]+ [0-9]+$")
+ set(ENV{CMAKE_GENERATOR_PLATFORM} "invalid")
+ # Envvar shouldn't affect existing build tree
+ run_cmake_command(Envgen-platform-existing ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build Envgen-build)
+ if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ")
+ set(RunCMake-stderr-file "Envgen-platform-invalid-stderr-vs9.txt")
+ endif()
+ run_cmake_command(Envgen-platform-invalid ${CMAKE_COMMAND} ${source_dir})
+ unset(RunCMake-stderr-file)
+ # Command line -G implies -A""
+ run_cmake_command(Envgen-G-implicit-platform ${CMAKE_COMMAND} -G "${RunCMake_GENERATOR}" ${source_dir})
+ if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ")
+ set(RunCMake-stderr-file "Envgen-A-platform-stderr-vs9.txt")
+ endif()
+ run_cmake_command(Envgen-A-platform ${CMAKE_COMMAND} -A "fromcli" ${source_dir})
+ unset(RunCMake-stderr-file)
+ unset(ENV{CMAKE_GENERATOR_PLATFORM})
+ endif()
+ # Instance is available since VS 2017.
+ if(RunCMake_GENERATOR MATCHES "Visual Studio (15|16).*")
+ set(ENV{CMAKE_GENERATOR_INSTANCE} "invalid")
+ # Envvar shouldn't affect existing build tree
+ run_cmake_command(Envgen-instance-existing ${CMAKE_COMMAND} -E chdir ..
+ ${CMAKE_COMMAND} --build Envgen-build)
+ run_cmake_command(Envgen-instance-invalid ${CMAKE_COMMAND} ${source_dir})
+ unset(ENV{CMAKE_GENERATOR_INSTANCE})
+ endif()
+ unset(ENV{CMAKE_GENERATOR})
+ endif()
+endfunction()
+run_EnvironmentGenerator()
+
if(RunCMake_GENERATOR STREQUAL "Ninja")
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Build-build)
@@ -238,10 +334,16 @@ file(MAKE_DIRECTORY ${out})
file(WRITE ${outfile} "")
run_cmake_command(E_make_directory-three-directories
${CMAKE_COMMAND} -E make_directory ${out}/d1 ${out}/d2 ${out}/d2)
+run_cmake_command(E_remove_directory-three-directories
+ ${CMAKE_COMMAND} -E remove_directory ${out}/d1 ${out}/d2 ${out}/d2)
run_cmake_command(E_make_directory-directory-with-parent
${CMAKE_COMMAND} -E make_directory ${out}/parent/child)
-run_cmake_command(E_make_directory-three-directories-and-file
+run_cmake_command(E_remove_directory-directory-with-parent
+ ${CMAKE_COMMAND} -E remove_directory ${out}/parent)
+run_cmake_command(E_make_directory-two-directories-and-file
${CMAKE_COMMAND} -E make_directory ${out}/d1 ${out}/d2 ${outfile})
+run_cmake_command(E_remove_directory-two-directories-and-file
+ ${CMAKE_COMMAND} -E remove_directory ${out}/d1 ${out}/d2 ${outfile})
unset(out)
unset(outfile)
@@ -425,4 +527,8 @@ function(reject_fifo)
endfunction()
if(CMAKE_HOST_UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
reject_fifo()
+ run_cmake_command(closed_stdin sh -c "\"${CMAKE_COMMAND}\" --version <&-")
+ run_cmake_command(closed_stdout sh -c "\"${CMAKE_COMMAND}\" --version >&-")
+ run_cmake_command(closed_stderr sh -c "\"${CMAKE_COMMAND}\" --version 2>&-")
+ run_cmake_command(closed_stdall sh -c "\"${CMAKE_COMMAND}\" --version <&- >&- 2>&-")
endif()
diff --git a/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake b/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake
new file mode 100644
index 000000000..fd4e67df1
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake
@@ -0,0 +1,15 @@
+if(CMAKE_INSTALL_PREFIX)
+ message("CMAKE_INSTALL_PREFIX is ${CMAKE_INSTALL_PREFIX}")
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+ message("CMAKE_INSTALL_COMPONENT is ${CMAKE_INSTALL_COMPONENT}")
+endif()
+
+if(CMAKE_INSTALL_CONFIG_NAME)
+ message("CMAKE_INSTALL_CONFIG_NAME is ${CMAKE_INSTALL_CONFIG_NAME}")
+endif()
+
+if(CMAKE_INSTALL_DO_STRIP)
+ message("CMAKE_INSTALL_DO_STRIP is ${CMAKE_INSTALL_DO_STRIP}")
+endif()
diff --git a/Tests/RunCMake/CommandLine/install-bad-dir-result.txt b/Tests/RunCMake/CommandLine/install-bad-dir-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-bad-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt b/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt
new file mode 100644
index 000000000..320aecc8f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Error processing file:
diff --git a/Tests/RunCMake/CommandLine/install-no-dir-result.txt b/Tests/RunCMake/CommandLine/install-no-dir-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-no-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt b/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt
new file mode 100644
index 000000000..d64f6385f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt
@@ -0,0 +1 @@
+^Usage: cmake --install <dir> \[options\]
diff --git a/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt b/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt b/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt
new file mode 100644
index 000000000..f7b1583ad
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt
@@ -0,0 +1,4 @@
+CMAKE_INSTALL_PREFIX is /var/test
+CMAKE_INSTALL_COMPONENT is pack
+CMAKE_INSTALL_CONFIG_NAME is sample
+CMAKE_INSTALL_DO_STRIP is 1
diff --git a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
index 12635dbfb..a64af9524 100644
--- a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
@@ -4,25 +4,33 @@ function(external_command_test NAME)
run_cmake_command(${NAME} ${CMAKE_COMMAND} -E ${ARGN})
endfunction()
-external_command_test(bad-opt1 tar cvf bad.tar --bad)
-external_command_test(bad-mtime1 tar cvf bad.tar --mtime=bad .)
-external_command_test(bad-from1 tar cvf bad.tar --files-from=bad)
-external_command_test(bad-from2 tar cvf bad.tar --files-from=.)
-external_command_test(bad-from3 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from3.txt)
-external_command_test(bad-from4 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from4.txt)
-external_command_test(bad-from5 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from5.txt)
-external_command_test(end-opt1 tar cvf bad.tar -- --bad)
-external_command_test(end-opt2 tar cvf bad.tar --)
-external_command_test(mtime tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC")
-external_command_test(bad-format tar cvf bad.tar "--format=bad-format")
-external_command_test(zip-bz2 tar cvjf bad.tar "--format=zip")
-external_command_test(7zip-gz tar cvzf bad.tar "--format=7zip")
+external_command_test(without-files tar cvf bad.tar)
+external_command_test(bad-opt1 tar cvf bad.tar --bad)
+external_command_test(bad-mtime1 tar cvf bad.tar --mtime=bad .)
+external_command_test(bad-from1 tar cvf bad.tar --files-from=bad)
+external_command_test(bad-from2 tar cvf bad.tar --files-from=.)
+external_command_test(bad-from3 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from3.txt)
+external_command_test(bad-from4 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from4.txt)
+external_command_test(bad-from5 tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from5.txt)
+external_command_test(bad-file tar cf bad.tar badfile.txt ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-without-action tar f bad.tar ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-wrong-flag tar cvfq bad.tar ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(end-opt1 tar cvf bad.tar -- --bad)
+external_command_test(end-opt2 tar cvf bad.tar --)
+external_command_test(mtime tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-format tar cvf bad.tar "--format=bad-format" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(zip-bz2 tar cvjf bad.tar "--format=zip" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(7zip-gz tar cvzf bad.tar "--format=7zip" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
run_cmake(7zip)
run_cmake(gnutar)
run_cmake(gnutar-gz)
run_cmake(pax)
run_cmake(pax-xz)
+run_cmake(pax-zstd)
run_cmake(paxr)
run_cmake(paxr-bz2)
run_cmake(zip)
+
+# Extracting only selected files or directories
+run_cmake(zip-filtered)
diff --git a/Tests/RunCMake/CommandLineTar/bad-file-result.txt b/Tests/RunCMake/CommandLineTar/bad-file-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt
new file mode 100644
index 000000000..1f9f748ce
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Unable to read from file 'badfile.txt': .*
+CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
index 1417d4d32..fb0702a1a 100644
--- a/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+^CMake Error: Unable to read from file 'does-not-exist':.*
CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
index 1417d4d32..fb0702a1a 100644
--- a/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+^CMake Error: Unable to read from file 'does-not-exist':.*
CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/bad-without-action-result.txt b/Tests/RunCMake/CommandLineTar/bad-without-action-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-without-action-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt
new file mode 100644
index 000000000..2fec25467
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: tar: No action specified. Please choose: 't' \(list\), 'c' \(create\) or 'x' \(extract\)$
diff --git a/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt
new file mode 100644
index 000000000..d5c1e0163
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt
@@ -0,0 +1 @@
+^tar: Unknown argument: q
diff --git a/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt b/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
index 1fddf6d2d..1342dc8d0 100644
--- a/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file '--bad':.*
+^CMake Error: Unable to read from file '--bad':.*
CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt b/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt
new file mode 100644
index 000000000..70166f540
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt
@@ -0,0 +1 @@
+^tar: No files or directories specified
diff --git a/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake b/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
index 5f2674a8f..53ee96186 100644
--- a/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
+++ b/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
@@ -1,9 +1,9 @@
set(OUTPUT_NAME "test.tar.gz")
-set(COMPRESSION_FLAGS cvzf)
+set(COMPRESSION_FLAGS -cvzf)
set(COMPRESSION_OPTIONS --format=gnutar)
-set(DECOMPRESSION_FLAGS xvzf)
+set(DECOMPRESSION_FLAGS -xvzf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
diff --git a/Tests/RunCMake/CommandLineTar/pax-zstd.cmake b/Tests/RunCMake/CommandLineTar/pax-zstd.cmake
new file mode 100644
index 000000000..c2a304d80
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/pax-zstd.cmake
@@ -0,0 +1,10 @@
+set(OUTPUT_NAME "test.tar.zstd")
+
+set(COMPRESSION_FLAGS cvf)
+set(COMPRESSION_OPTIONS --format=pax --zstd)
+
+set(DECOMPRESSION_FLAGS xvf)
+
+include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
+
+check_magic("28b52ffd0058" LIMIT 6 HEX)
diff --git a/Tests/RunCMake/CommandLineTar/pax.cmake b/Tests/RunCMake/CommandLineTar/pax.cmake
index 60ed2385c..77f74d135 100644
--- a/Tests/RunCMake/CommandLineTar/pax.cmake
+++ b/Tests/RunCMake/CommandLineTar/pax.cmake
@@ -1,9 +1,9 @@
set(OUTPUT_NAME "test.tar")
-set(COMPRESSION_FLAGS cvf)
+set(COMPRESSION_FLAGS -cvf)
set(COMPRESSION_OPTIONS --format=pax)
-set(DECOMPRESSION_FLAGS xvf)
+set(DECOMPRESSION_FLAGS -xvf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
diff --git a/Tests/RunCMake/CommandLineTar/roundtrip.cmake b/Tests/RunCMake/CommandLineTar/roundtrip.cmake
index dc1c88528..fa63d1240 100644
--- a/Tests/RunCMake/CommandLineTar/roundtrip.cmake
+++ b/Tests/RunCMake/CommandLineTar/roundtrip.cmake
@@ -47,7 +47,11 @@ file(REMOVE_RECURSE ${FULL_DECOMPRESS_DIR})
file(MAKE_DIRECTORY ${FULL_DECOMPRESS_DIR})
run_tar(${CMAKE_CURRENT_BINARY_DIR} ${COMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${COMPRESSION_OPTIONS} ${COMPRESS_DIR})
-run_tar(${FULL_DECOMPRESS_DIR} ${DECOMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${DECOMPRESSION_OPTIONS})
+run_tar(${FULL_DECOMPRESS_DIR} ${DECOMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${DECOMPRESSION_OPTIONS} -- ${DECOMPRESSION_PATHNAMES})
+
+if(CUSTOM_CHECK_FILES)
+ set(CHECK_FILES ${CUSTOM_CHECK_FILES})
+endif()
foreach(file ${CHECK_FILES})
set(input ${FULL_COMPRESS_DIR}/${file})
@@ -69,6 +73,14 @@ foreach(file ${CHECK_FILES})
endif()
endforeach()
+foreach(file ${NOT_EXISTING_FILES_CHECK})
+ set(output ${FULL_DECOMPRESS_DIR}/${COMPRESS_DIR}/${file})
+
+ if(EXISTS ${output})
+ message(SEND_ERROR "File ${output} exists but it shouldn't")
+ endif()
+endforeach()
+
function(check_magic EXPECTED)
file(READ ${FULL_OUTPUT_NAME} ACTUAL
${ARGN}
diff --git a/Tests/RunCMake/CommandLineTar/test-file.txt b/Tests/RunCMake/CommandLineTar/test-file.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/test-file.txt
diff --git a/Tests/RunCMake/CommandLineTar/without-files-stderr.txt b/Tests/RunCMake/CommandLineTar/without-files-stderr.txt
new file mode 100644
index 000000000..70166f540
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/without-files-stderr.txt
@@ -0,0 +1 @@
+^tar: No files or directories specified
diff --git a/Tests/RunCMake/CommandLineTar/zip-filtered.cmake b/Tests/RunCMake/CommandLineTar/zip-filtered.cmake
new file mode 100644
index 000000000..c13210ef0
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/zip-filtered.cmake
@@ -0,0 +1,28 @@
+set(OUTPUT_NAME "test.zip")
+
+set(COMPRESSION_FLAGS cvf)
+set(COMPRESSION_OPTIONS --format=zip)
+
+set(DECOMPRESSION_FLAGS xvf)
+set(LIST_ARCHIVE TRUE)
+set(DECOMPRESSION_PATHNAMES
+ compress_dir/f1.txt # Decompress only file
+ compress_dir/d1 # and whole directory
+)
+
+set(CUSTOM_CHECK_FILES
+ "f1.txt"
+ "d1/f1.txt"
+)
+
+# This files shouldn't exists
+set(NOT_EXISTING_FILES_CHECK
+ "d 2/f1.txt"
+ "d + 3/f1.txt"
+ "d_4/f1.txt"
+ "d-4/f1.txt"
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
+
+check_magic("504b0304" LIMIT 4 HEX)
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake
new file mode 100644
index 000000000..9ca610660
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/output")
+ message(FATAL_ERROR "Failed to create output: ${RunCMake_TEST_BINARY_DIR}/output")
+endif()
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake
new file mode 100644
index 000000000..d9059ca6e
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake
@@ -0,0 +1,14 @@
+set(CMAKE_CROSSCOMPILING 1)
+
+# Executable: Return error code different from 0
+add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
+
+add_custom_command(OUTPUT output
+ COMMAND generated_exe_emulator_expected
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
+ DEPENDS generated_exe_emulator_expected)
+
+add_custom_target(ensure_build ALL
+ SOURCES
+ ${CMAKE_CURRENT_BINARY_DIR}/output
+)
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake
new file mode 100644
index 000000000..13c0db96a
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/AddCustomCommandWithArg-build-check.cmake)
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake
new file mode 100644
index 000000000..dcd80d53a
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake
@@ -0,0 +1,9 @@
+set(CMAKE_CROSSCOMPILING 1)
+
+# Executable: Return error code different from 0
+add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
+
+add_custom_target(generate_output ALL
+ generated_exe_emulator_expected
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
+ DEPENDS generated_exe_emulator_expected)
diff --git a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
index 71aaad19b..97b7b5a31 100644
--- a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
@@ -11,13 +11,18 @@ function(CustomCommandGenerator_run_and_build case)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
set(RunCMake_TEST_NO_CLEAN 1)
- set(RunCMake_TEST_OPTIONS
- "-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${case})
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
endfunction()
+set(RunCMake_TEST_OPTIONS
+"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
CustomCommandGenerator_run_and_build(AddCustomCommand)
CustomCommandGenerator_run_and_build(AddCustomTarget)
+
+set(RunCMake_TEST_OPTIONS
+"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND_ARG}\;custom_argument")
+CustomCommandGenerator_run_and_build(AddCustomCommandWithArg)
+CustomCommandGenerator_run_and_build(AddCustomTargetWithArg)
diff --git a/Tests/RunCMake/FileAPI/check_index.pyc b/Tests/RunCMake/FileAPI/check_index.pyc
index 72fd370cd..1eaf03dc3 100644
--- a/Tests/RunCMake/FileAPI/check_index.pyc
+++ b/Tests/RunCMake/FileAPI/check_index.pyc
Binary files differ
diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
index b08ef5a15..4c2e35fcc 100644
--- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
+++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
@@ -3,6 +3,7 @@ CMake Error at OutputNameMatchesObjects.cmake:[0-9]+ \(file\):
\$<TARGET_OBJECTS:foo>
- Objects of target "foo" referenced but is not an OBJECT library.
+ Objects of target "foo" referenced but is not an allowed library types
+ \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake
index daa7c49ca..84825feea 100644
--- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake
+++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake
@@ -1,11 +1,8 @@
enable_language(CXX)
file(GENERATE
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<BOOL:$<TARGET_OBJECTS:foo>>somefile.cpp"
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>/somefile.cpp"
CONTENT "static const char content[] = \"$<TARGET_OBJECTS:foo>\";\n"
)
-add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/input.txt"
- COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/input.txt" "${CMAKE_CURRENT_BINARY_DIR}")
-
-add_executable(foo empty.cpp "${CMAKE_CURRENT_BINARY_DIR}/1somefile.cpp" "${CMAKE_CURRENT_BINARY_DIR}/input.txt")
+add_library(foo INTERFACE )
diff --git a/Tests/RunCMake/FindBoost/CMP0093-NEW-stdout.txt b/Tests/RunCMake/FindBoost/CMP0093-NEW-stdout.txt
new file mode 100644
index 000000000..62a6d39cb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-NEW-stdout.txt
@@ -0,0 +1 @@
+-- Boost_VERSION=1.70.0
diff --git a/Tests/RunCMake/FindBoost/CMP0093-NEW.cmake b/Tests/RunCMake/FindBoost/CMP0093-NEW.cmake
new file mode 100644
index 000000000..64f44d25b
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0093 NEW)
+include(ModuleMode.cmake)
diff --git a/Tests/RunCMake/FindBoost/CMP0093-OLD-stdout.txt b/Tests/RunCMake/FindBoost/CMP0093-OLD-stdout.txt
new file mode 100644
index 000000000..9e51e35c8
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-OLD-stdout.txt
@@ -0,0 +1 @@
+-- Boost_VERSION=107000
diff --git a/Tests/RunCMake/FindBoost/CMP0093-OLD.cmake b/Tests/RunCMake/FindBoost/CMP0093-OLD.cmake
new file mode 100644
index 000000000..69a3a9542
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0093 OLD)
+include(ModuleMode.cmake)
diff --git a/Tests/RunCMake/FindBoost/CMP0093-UNSET-stdout.txt b/Tests/RunCMake/FindBoost/CMP0093-UNSET-stdout.txt
new file mode 100644
index 000000000..9e51e35c8
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-UNSET-stdout.txt
@@ -0,0 +1 @@
+-- Boost_VERSION=107000
diff --git a/Tests/RunCMake/FindBoost/CMP0093-UNSET.cmake b/Tests/RunCMake/FindBoost/CMP0093-UNSET.cmake
new file mode 100644
index 000000000..974094a0e
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMP0093-UNSET.cmake
@@ -0,0 +1 @@
+include(ModuleMode.cmake)
diff --git a/Tests/RunCMake/FindBoost/CMakePackage-stdout.txt b/Tests/RunCMake/FindBoost/CMakePackage-stdout.txt
index 664e4a5f8..0a67488a8 100644
--- a/Tests/RunCMake/FindBoost/CMakePackage-stdout.txt
+++ b/Tests/RunCMake/FindBoost/CMakePackage-stdout.txt
@@ -1,3 +1,2 @@
--- Boost 1\.12345 found\.
--- Found Boost components:
- date_time
+-- Found Boost: [^
+]* \(found suitable version "1\.12345", minimum required is "1\.12345"\) found components: date_time
diff --git a/Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake
index e69de29bb..36a9abd5c 100644
--- a/Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake
+++ b/Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake
@@ -0,0 +1,4 @@
+set(Boost_DATE_TIME_FOUND 1)
+add_library(Boost::boost INTERFACE IMPORTED)
+add_library(Boost::headers INTERFACE IMPORTED)
+add_library(Boost::date_time UNKNOWN IMPORTED)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfig.cmake
new file mode 100644
index 000000000..539267d92
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfig.cmake
@@ -0,0 +1,140 @@
+# Copyright 2019 Peter Dimov
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
+
+# This CMake configuration file, installed as part of the Boost build
+# and installation procedure done by `b2 install`, provides support
+# for find_package(Boost).
+#
+# It's roughly, but not perfectly, compatible with the behavior
+# of find_package(Boost) as provided by FindBoost.cmake.
+#
+# A typical use might be
+#
+# find_package(Boost 1.70 REQUIRED COMPONENTS filesystem regex PATHS C:/Boost)
+#
+# On success, the above invocation would define the targets Boost::headers,
+# Boost::filesystem and Boost::regex. Boost::headers represents all
+# header-only libraries. An alias, Boost::boost, for Boost::headers is
+# provided for compatibility.
+#
+# Since Boost libraries can coexist in many variants - 32/64 bit,
+# static/dynamic runtime, debug/release, the following variables can be used
+# to control which variant is chosen:
+#
+# Boost_USE_DEBUG_LIBS: When OFF, disables debug libraries.
+# Boost_USE_RELEASE_LIBS: When OFF, disables release libraries.
+# Boost_USE_STATIC_LIBS: When ON, uses static Boost libraries; when OFF,
+# uses shared Boost libraries; when not set, the
+# default is to use shared when BUILD_SHARED_LIBS is
+# ON, static otherwise.
+# Boost_USE_STATIC_RUNTIME: When ON, uses Boost libraries linked against the
+# static runtime. The default is shared runtime.
+# Boost_USE_DEBUG_RUNTIME: When ON, uses Boost libraries linked against the
+# debug runtime. When OFF, against the release
+# runtime. The default is to use either.
+# Boost_COMPILER: The compiler that has been used to build Boost,
+# such as vc141, gcc7, clang37. The default is
+# determined from CMAKE_CXX_COMPILER_ID.
+
+message(STATUS "Found Boost ${Boost_VERSION} at ${Boost_DIR}")
+
+# Output requested configuration (f.ex. "REQUIRED COMPONENTS filesystem")
+
+if(Boost_FIND_QUIETLY)
+ set(_BOOST_CONFIG "${_BOOST_CONFIG} QUIET")
+endif()
+
+if(Boost_FIND_REQUIRED)
+ set(_BOOST_CONFIG "${_BOOST_CONFIG} REQUIRED")
+endif()
+
+foreach(__boost_comp IN LISTS Boost_FIND_COMPONENTS)
+ if(${Boost_FIND_REQUIRED_${__boost_comp}})
+ list(APPEND _BOOST_COMPONENTS ${__boost_comp})
+ else()
+ list(APPEND _BOOST_OPTIONAL_COMPONENTS ${__boost_comp})
+ endif()
+endforeach()
+
+if(_BOOST_COMPONENTS)
+ set(_BOOST_CONFIG "${_BOOST_CONFIG} COMPONENTS ${_BOOST_COMPONENTS}")
+endif()
+
+if(_BOOST_OPTIONAL_COMPONENTS)
+ set(_BOOST_CONFIG "${_BOOST_CONFIG} OPTIONAL_COMPONENTS ${_BOOST_OPTIONAL_COMPONENTS}")
+endif()
+
+if(_BOOST_CONFIG)
+ message(STATUS " Requested configuration:${_BOOST_CONFIG}")
+endif()
+
+unset(_BOOST_CONFIG)
+unset(_BOOST_COMPONENTS)
+unset(_BOOST_OPTIONAL_COMPONENTS)
+
+# find_dependency doesn't forward arguments until 3.9, so we have to roll our own
+
+macro(boost_find_dependency dep req)
+
+ set(_BOOST_QUIET)
+ if(Boost_FIND_QUIETLY)
+ set(_BOOST_QUIET QUIET)
+ endif()
+
+ set(_BOOST_REQUIRED)
+ if(${req} AND Boost_FIND_REQUIRED)
+ set(_BOOST_REQUIRED REQUIRED)
+ endif()
+
+ get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+
+ if(Boost_DEBUG)
+ message(STATUS "BoostConfig: find_package(boost_${dep} ${Boost_VERSION} EXACT CONFIG ${_BOOST_REQUIRED} ${_BOOST_QUIET} HINTS ${_BOOST_CMAKEDIR})")
+ endif()
+ find_package(boost_${dep} ${Boost_VERSION} EXACT CONFIG ${_BOOST_REQUIRED} ${_BOOST_QUIET} HINTS ${_BOOST_CMAKEDIR})
+
+ string(TOUPPER ${dep} _BOOST_DEP)
+ set(Boost_${_BOOST_DEP}_FOUND ${boost_${dep}_FOUND})
+
+ unset(_BOOST_REQUIRED)
+ unset(_BOOST_QUIET)
+ unset(_BOOST_CMAKEDIR)
+ unset(_BOOST_DEP)
+
+endmacro()
+
+# Find boost_headers
+
+boost_find_dependency(headers 1)
+
+if(NOT boost_headers_FOUND)
+
+ set(Boost_FOUND 0)
+ set(Boost_NOT_FOUND_MESSAGE "A required dependency, boost_headers, has not been found.")
+
+ return()
+
+endif()
+
+# Find components
+
+foreach(__boost_comp IN LISTS Boost_FIND_COMPONENTS)
+
+ boost_find_dependency(${__boost_comp} ${Boost_FIND_REQUIRED_${__boost_comp}})
+
+endforeach()
+
+# Compatibility targets
+
+if(NOT TARGET Boost::boost)
+
+ add_library(Boost::boost INTERFACE IMPORTED)
+ set_property(TARGET Boost::boost APPEND PROPERTY INTERFACE_LINK_LIBRARIES Boost::headers)
+
+ # All Boost:: targets already disable autolink
+ add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
+ add_library(Boost::disable_autolinking INTERFACE IMPORTED)
+ add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfigVersion.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfigVersion.cmake
new file mode 100644
index 000000000..114bba078
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfigVersion.cmake
@@ -0,0 +1,12 @@
+# Generated by Boost 1.70.0
+
+set(PACKAGE_VERSION 1.70.0)
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/BoostDetectToolset-1.70.0.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/BoostDetectToolset-1.70.0.cmake
new file mode 100644
index 000000000..2f1ac0199
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/BoostDetectToolset-1.70.0.cmake
@@ -0,0 +1 @@
+set(BOOST_DETECTED_TOOLSET "gcc7")
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config-version.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config-version.cmake
new file mode 100644
index 000000000..114bba078
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config-version.cmake
@@ -0,0 +1,12 @@
+# Generated by Boost 1.70.0
+
+set(PACKAGE_VERSION 1.70.0)
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config.cmake
new file mode 100644
index 000000000..5d798b52a
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config.cmake
@@ -0,0 +1,98 @@
+# Generated by Boost 1.70.0
+
+if(TARGET Boost::chrono)
+ return()
+endif()
+
+message(STATUS "Found boost_chrono ${boost_chrono_VERSION} at ${boost_chrono_DIR}")
+
+# Compute the include and library directories relative to this file.
+get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)
+get_filename_component(_BOOST_LIBDIR "${_BOOST_CMAKEDIR}/../" ABSOLUTE)
+
+# Create imported target Boost::chrono
+add_library(Boost::chrono UNKNOWN IMPORTED)
+
+set_target_properties(Boost::chrono PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_BOOST_INCLUDEDIR}"
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB"
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../BoostDetectToolset-1.70.0.cmake)
+
+if(Boost_DEBUG)
+ message(STATUS "Scanning ${CMAKE_CURRENT_LIST_DIR}/libboost_chrono-variant*.cmake")
+endif()
+
+file(GLOB __boost_variants "${CMAKE_CURRENT_LIST_DIR}/libboost_chrono-variant*.cmake")
+
+macro(_BOOST_SKIPPED fname reason)
+ if(Boost_DEBUG)
+ message(STATUS " ... skipped ${fname} (${reason})")
+ endif()
+ list(APPEND __boost_skipped "${fname} (${reason})")
+endmacro()
+
+foreach(f IN LISTS __boost_variants)
+ if(Boost_DEBUG)
+ message(STATUS " Including ${f}")
+ endif()
+ include(${f})
+endforeach()
+
+unset(_BOOST_LIBDIR)
+unset(_BOOST_INCLUDEDIR)
+unset(_BOOST_CMAKEDIR)
+
+get_target_property(__boost_configs Boost::chrono IMPORTED_CONFIGURATIONS)
+
+if(__boost_variants AND NOT __boost_configs)
+ message(STATUS "No suitable boost_chrono variant has been identified!")
+ if(NOT Boost_DEBUG)
+ foreach(s IN LISTS __boost_skipped)
+ message(STATUS " ${s}")
+ endforeach()
+ endif()
+ set(boost_chrono_FOUND 0)
+ set(boost_chrono_NOT_FOUND_MESSAGE "No suitable build variant has been found.")
+ unset(__boost_skipped)
+ unset(__boost_configs)
+ unset(__boost_variants)
+ unset(_BOOST_CHRONO_DEPS)
+ return()
+endif()
+
+unset(__boost_skipped)
+unset(__boost_configs)
+unset(__boost_variants)
+
+if(_BOOST_CHRONO_DEPS)
+ list(REMOVE_DUPLICATES _BOOST_CHRONO_DEPS)
+ message(STATUS "Adding boost_chrono dependencies: ${_BOOST_CHRONO_DEPS}")
+endif()
+
+foreach(dep_boost_chrono IN LISTS _BOOST_CHRONO_DEPS)
+ set(_BOOST_QUIET)
+ if(boost_chrono_FIND_QUIETLY)
+ set(_BOOST_QUIET QUIET)
+ endif()
+ set(_BOOST_REQUIRED)
+ if(boost_chrono_FIND_REQUIRED)
+ set(_BOOST_REQUIRED REQUIRED)
+ endif()
+ get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+ find_package(boost_${dep_boost_chrono} 1.70.0 EXACT CONFIG ${_BOOST_REQUIRED} ${_BOOST_QUIET} HINTS ${_BOOST_CMAKEDIR})
+ set_property(TARGET Boost::chrono APPEND PROPERTY INTERFACE_LINK_LIBRARIES Boost::${dep_boost_chrono})
+ unset(_BOOST_QUIET)
+ unset(_BOOST_REQUIRED)
+ unset(_BOOST_CMAKEDIR)
+ if(NOT boost_${dep_boost_chrono}_FOUND)
+ set(boost_chrono_FOUND 0)
+ set(boost_chrono_NOT_FOUND_MESSAGE "A required dependency, boost_${dep_boost_chrono}, has not been found.")
+ unset(_BOOST_CHRONO_DEPS)
+ return()
+ endif()
+endforeach()
+
+unset(_BOOST_CHRONO_DEPS)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-shared.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-shared.cmake
new file mode 100644
index 000000000..7f07aed47
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-shared.cmake
@@ -0,0 +1,62 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=shared
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "shared, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(NOT BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "shared, BUILD_SHARED_LIBS not ON, set Boost_USE_STATIC_LIBS=OFF to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.so.1.70.0" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_chrono.so.1.70.0")
+
+# Target file name: libboost_chrono.so.1.70.0
+set_property(TARGET Boost::chrono APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::chrono PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_chrono.so.1.70.0"
+ )
+
+set_target_properties(Boost::chrono PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_CHRONO_DYN_LINK"
+ )
+
+list(APPEND _BOOST_CHRONO_DEPS headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-static.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-static.cmake
new file mode 100644
index 000000000..d7477b4d7
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-static.cmake
@@ -0,0 +1,58 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_chrono.a" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=static
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND NOT Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.a" "static, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.a" "static, BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}, set Boost_USE_STATIC_LIBS=ON to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_chrono.a" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_chrono.a" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_chrono.a" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_chrono.a")
+
+# Target file name: libboost_chrono.a
+set_property(TARGET Boost::chrono APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::chrono PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_chrono.a"
+ )
+
+list(APPEND _BOOST_CHRONO_DEPS headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config-version.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config-version.cmake
new file mode 100644
index 000000000..114bba078
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config-version.cmake
@@ -0,0 +1,12 @@
+# Generated by Boost 1.70.0
+
+set(PACKAGE_VERSION 1.70.0)
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config.cmake
new file mode 100644
index 000000000..0305ecd5c
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config.cmake
@@ -0,0 +1,20 @@
+# Generated by Boost 1.70.0
+
+if(TARGET Boost::headers)
+ return()
+endif()
+
+message(STATUS "Found boost_headers ${boost_headers_VERSION} at ${boost_headers_DIR}")
+
+# Compute the include and library directories relative to this file.
+get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)
+get_filename_component(_BOOST_LIBDIR "${_BOOST_CMAKEDIR}/../" ABSOLUTE)
+
+# Create imported target Boost::headers
+add_library(Boost::headers INTERFACE IMPORTED)
+
+set_target_properties(Boost::headers PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_BOOST_INCLUDEDIR}"
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB"
+)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config-version.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config-version.cmake
new file mode 100644
index 000000000..114bba078
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config-version.cmake
@@ -0,0 +1,12 @@
+# Generated by Boost 1.70.0
+
+set(PACKAGE_VERSION 1.70.0)
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config.cmake
new file mode 100644
index 000000000..40b10d0c6
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config.cmake
@@ -0,0 +1,98 @@
+# Generated by Boost 1.70.0
+
+if(TARGET Boost::system)
+ return()
+endif()
+
+message(STATUS "Found boost_system ${boost_system_VERSION} at ${boost_system_DIR}")
+
+# Compute the include and library directories relative to this file.
+get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)
+get_filename_component(_BOOST_LIBDIR "${_BOOST_CMAKEDIR}/../" ABSOLUTE)
+
+# Create imported target Boost::system
+add_library(Boost::system UNKNOWN IMPORTED)
+
+set_target_properties(Boost::system PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_BOOST_INCLUDEDIR}"
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB"
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../BoostDetectToolset-1.70.0.cmake)
+
+if(Boost_DEBUG)
+ message(STATUS "Scanning ${CMAKE_CURRENT_LIST_DIR}/libboost_system-variant*.cmake")
+endif()
+
+file(GLOB __boost_variants "${CMAKE_CURRENT_LIST_DIR}/libboost_system-variant*.cmake")
+
+macro(_BOOST_SKIPPED fname reason)
+ if(Boost_DEBUG)
+ message(STATUS " ... skipped ${fname} (${reason})")
+ endif()
+ list(APPEND __boost_skipped "${fname} (${reason})")
+endmacro()
+
+foreach(f IN LISTS __boost_variants)
+ if(Boost_DEBUG)
+ message(STATUS " Including ${f}")
+ endif()
+ include(${f})
+endforeach()
+
+unset(_BOOST_LIBDIR)
+unset(_BOOST_INCLUDEDIR)
+unset(_BOOST_CMAKEDIR)
+
+get_target_property(__boost_configs Boost::system IMPORTED_CONFIGURATIONS)
+
+if(__boost_variants AND NOT __boost_configs)
+ message(STATUS "No suitable boost_system variant has been identified!")
+ if(NOT Boost_DEBUG)
+ foreach(s IN LISTS __boost_skipped)
+ message(STATUS " ${s}")
+ endforeach()
+ endif()
+ set(boost_system_FOUND 0)
+ set(boost_system_NOT_FOUND_MESSAGE "No suitable build variant has been found.")
+ unset(__boost_skipped)
+ unset(__boost_configs)
+ unset(__boost_variants)
+ unset(_BOOST_SYSTEM_DEPS)
+ return()
+endif()
+
+unset(__boost_skipped)
+unset(__boost_configs)
+unset(__boost_variants)
+
+if(_BOOST_SYSTEM_DEPS)
+ list(REMOVE_DUPLICATES _BOOST_SYSTEM_DEPS)
+ message(STATUS "Adding boost_system dependencies: ${_BOOST_SYSTEM_DEPS}")
+endif()
+
+foreach(dep_boost_system IN LISTS _BOOST_SYSTEM_DEPS)
+ set(_BOOST_QUIET)
+ if(boost_system_FIND_QUIETLY)
+ set(_BOOST_QUIET QUIET)
+ endif()
+ set(_BOOST_REQUIRED)
+ if(boost_system_FIND_REQUIRED)
+ set(_BOOST_REQUIRED REQUIRED)
+ endif()
+ get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+ find_package(boost_${dep_boost_system} 1.70.0 EXACT CONFIG ${_BOOST_REQUIRED} ${_BOOST_QUIET} HINTS ${_BOOST_CMAKEDIR})
+ set_property(TARGET Boost::system APPEND PROPERTY INTERFACE_LINK_LIBRARIES Boost::${dep_boost_system})
+ unset(_BOOST_QUIET)
+ unset(_BOOST_REQUIRED)
+ unset(_BOOST_CMAKEDIR)
+ if(NOT boost_${dep_boost_system}_FOUND)
+ set(boost_system_FOUND 0)
+ set(boost_system_NOT_FOUND_MESSAGE "A required dependency, boost_${dep_boost_system}, has not been found.")
+ unset(_BOOST_SYSTEM_DEPS)
+ return()
+ endif()
+endforeach()
+
+unset(_BOOST_SYSTEM_DEPS)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-shared.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-shared.cmake
new file mode 100644
index 000000000..751db32c3
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-shared.cmake
@@ -0,0 +1,62 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=shared
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "shared, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(NOT BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "shared, BUILD_SHARED_LIBS not ON, set Boost_USE_STATIC_LIBS=OFF to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_system.so.1.70.0" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_system.so.1.70.0")
+
+# Target file name: libboost_system.so.1.70.0
+set_property(TARGET Boost::system APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::system PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_system.so.1.70.0"
+ )
+
+set_target_properties(Boost::system PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_SYSTEM_DYN_LINK"
+ )
+
+list(APPEND _BOOST_SYSTEM_DEPS headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-static.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-static.cmake
new file mode 100644
index 000000000..b10e0b9e3
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-static.cmake
@@ -0,0 +1,58 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_system.a" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=static
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND NOT Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_system.a" "static, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_system.a" "static, BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}, set Boost_USE_STATIC_LIBS=ON to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_system.a" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_system.a" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_system.a" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_system.a")
+
+# Target file name: libboost_system.a
+set_property(TARGET Boost::system APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::system PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_system.a"
+ )
+
+list(APPEND _BOOST_SYSTEM_DEPS headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config-version.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config-version.cmake
new file mode 100644
index 000000000..114bba078
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config-version.cmake
@@ -0,0 +1,12 @@
+# Generated by Boost 1.70.0
+
+set(PACKAGE_VERSION 1.70.0)
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config.cmake
new file mode 100644
index 000000000..b0d0e5403
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config.cmake
@@ -0,0 +1,98 @@
+# Generated by Boost 1.70.0
+
+if(TARGET Boost::timer)
+ return()
+endif()
+
+message(STATUS "Found boost_timer ${boost_timer_VERSION} at ${boost_timer_DIR}")
+
+# Compute the include and library directories relative to this file.
+get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)
+get_filename_component(_BOOST_LIBDIR "${_BOOST_CMAKEDIR}/../" ABSOLUTE)
+
+# Create imported target Boost::timer
+add_library(Boost::timer UNKNOWN IMPORTED)
+
+set_target_properties(Boost::timer PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_BOOST_INCLUDEDIR}"
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB"
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../BoostDetectToolset-1.70.0.cmake)
+
+if(Boost_DEBUG)
+ message(STATUS "Scanning ${CMAKE_CURRENT_LIST_DIR}/libboost_timer-variant*.cmake")
+endif()
+
+file(GLOB __boost_variants "${CMAKE_CURRENT_LIST_DIR}/libboost_timer-variant*.cmake")
+
+macro(_BOOST_SKIPPED fname reason)
+ if(Boost_DEBUG)
+ message(STATUS " ... skipped ${fname} (${reason})")
+ endif()
+ list(APPEND __boost_skipped "${fname} (${reason})")
+endmacro()
+
+foreach(f IN LISTS __boost_variants)
+ if(Boost_DEBUG)
+ message(STATUS " Including ${f}")
+ endif()
+ include(${f})
+endforeach()
+
+unset(_BOOST_LIBDIR)
+unset(_BOOST_INCLUDEDIR)
+unset(_BOOST_CMAKEDIR)
+
+get_target_property(__boost_configs Boost::timer IMPORTED_CONFIGURATIONS)
+
+if(__boost_variants AND NOT __boost_configs)
+ message(STATUS "No suitable boost_timer variant has been identified!")
+ if(NOT Boost_DEBUG)
+ foreach(s IN LISTS __boost_skipped)
+ message(STATUS " ${s}")
+ endforeach()
+ endif()
+ set(boost_timer_FOUND 0)
+ set(boost_timer_NOT_FOUND_MESSAGE "No suitable build variant has been found.")
+ unset(__boost_skipped)
+ unset(__boost_configs)
+ unset(__boost_variants)
+ unset(_BOOST_TIMER_DEPS)
+ return()
+endif()
+
+unset(__boost_skipped)
+unset(__boost_configs)
+unset(__boost_variants)
+
+if(_BOOST_TIMER_DEPS)
+ list(REMOVE_DUPLICATES _BOOST_TIMER_DEPS)
+ message(STATUS "Adding boost_timer dependencies: ${_BOOST_TIMER_DEPS}")
+endif()
+
+foreach(dep_boost_timer IN LISTS _BOOST_TIMER_DEPS)
+ set(_BOOST_QUIET)
+ if(boost_timer_FIND_QUIETLY)
+ set(_BOOST_QUIET QUIET)
+ endif()
+ set(_BOOST_REQUIRED)
+ if(boost_timer_FIND_REQUIRED)
+ set(_BOOST_REQUIRED REQUIRED)
+ endif()
+ get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
+ find_package(boost_${dep_boost_timer} 1.70.0 EXACT CONFIG ${_BOOST_REQUIRED} ${_BOOST_QUIET} HINTS ${_BOOST_CMAKEDIR})
+ set_property(TARGET Boost::timer APPEND PROPERTY INTERFACE_LINK_LIBRARIES Boost::${dep_boost_timer})
+ unset(_BOOST_QUIET)
+ unset(_BOOST_REQUIRED)
+ unset(_BOOST_CMAKEDIR)
+ if(NOT boost_${dep_boost_timer}_FOUND)
+ set(boost_timer_FOUND 0)
+ set(boost_timer_NOT_FOUND_MESSAGE "A required dependency, boost_${dep_boost_timer}, has not been found.")
+ unset(_BOOST_TIMER_DEPS)
+ return()
+ endif()
+endforeach()
+
+unset(_BOOST_TIMER_DEPS)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-shared.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-shared.cmake
new file mode 100644
index 000000000..b35b59d64
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-shared.cmake
@@ -0,0 +1,62 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=shared
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "shared, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(NOT BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "shared, BUILD_SHARED_LIBS not ON, set Boost_USE_STATIC_LIBS=OFF to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_timer.so.1.70.0" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_timer.so.1.70.0")
+
+# Target file name: libboost_timer.so.1.70.0
+set_property(TARGET Boost::timer APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::timer PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_timer.so.1.70.0"
+ )
+
+set_target_properties(Boost::timer PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_TIMER_DYN_LINK"
+ )
+
+list(APPEND _BOOST_TIMER_DEPS chrono headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-static.cmake b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-static.cmake
new file mode 100644
index 000000000..37fa9c0a5
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-static.cmake
@@ -0,0 +1,58 @@
+# Generated by Boost 1.70.0
+
+# address-model=64
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ _BOOST_SKIPPED("libboost_timer.a" "64 bit, need 32")
+ return()
+endif()
+
+# layout=system
+
+# toolset=gcc8
+
+# link=static
+
+if(NOT "${Boost_USE_STATIC_LIBS}" STREQUAL "" AND NOT Boost_USE_STATIC_LIBS)
+ _BOOST_SKIPPED("libboost_timer.a" "static, Boost_USE_STATIC_LIBS=${Boost_USE_STATIC_LIBS}")
+ return()
+endif()
+
+if(BUILD_SHARED_LIBS)
+ _BOOST_SKIPPED("libboost_timer.a" "static, BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}, set Boost_USE_STATIC_LIBS=ON to override")
+ return()
+endif()
+
+# runtime-link=shared
+
+if(Boost_USE_STATIC_RUNTIME)
+ _BOOST_SKIPPED("libboost_timer.a" "shared runtime, Boost_USE_STATIC_RUNTIME=${Boost_USE_STATIC_RUNTIME}")
+ return()
+endif()
+
+# runtime-debugging=off
+
+if(Boost_USE_DEBUG_RUNTIME)
+ _BOOST_SKIPPED("libboost_timer.a" "release runtime, Boost_USE_DEBUG_RUNTIME=${Boost_USE_DEBUG_RUNTIME}")
+ return()
+endif()
+
+# threading=multi
+
+# variant=release
+
+if(NOT "${Boost_USE_RELEASE_LIBS}" STREQUAL "" AND NOT Boost_USE_RELEASE_LIBS)
+ _BOOST_SKIPPED("libboost_timer.a" "release, Boost_USE_RELEASE_LIBS=${Boost_USE_RELEASE_LIBS}")
+ return()
+endif()
+
+message(STATUS " libboost_timer.a")
+
+# Target file name: libboost_timer.a
+set_property(TARGET Boost::timer APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_target_properties(Boost::timer PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE CXX
+ IMPORTED_LOCATION_RELEASE "${_BOOST_LIBDIR}/libboost_timer.a"
+ )
+
+list(APPEND _BOOST_TIMER_DEPS chrono headers)
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfig.cmake
new file mode 100644
index 000000000..cf13b4ac3
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfig.cmake
@@ -0,0 +1,26 @@
+# No boost::boost target and all targets start with lowercase letters
+# Similar to https://github.com/boost-cmake/boost-cmake
+
+add_library(boost::headers INTERFACE IMPORTED)
+target_include_directories(boost::headers INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include")
+
+set(Boost_date_time_FOUND 1)
+add_library(boost::date_time UNKNOWN IMPORTED)
+set_target_properties(boost::date_time PROPERTIES
+ IMPORTED_CONFIGURATIONS RELEASE
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_date_time.a"
+ )
+set(Boost_python37_FOUND 1)
+add_library(boost::python UNKNOWN IMPORTED)
+set_target_properties(boost::python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python_release.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python.a"
+ )
+set(Boost_mpi_python2_FOUND 1)
+add_library(boost::mpi_python UNKNOWN IMPORTED)
+set_target_properties(boost::mpi_python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ )
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfigVersion.cmake b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfigVersion.cmake
new file mode 100644
index 000000000..b4b606000
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.70.42)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 70 AND PACKAGE_FIND_VERSION_PATCH EQUAL 42)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/include/boost/version.hpp b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/include/boost/version.hpp
new file mode 100644
index 000000000..fe8e72c6d
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/include/boost/version.hpp
@@ -0,0 +1,34 @@
+// Boost version.hpp configuration header file
+// ------------------------------//
+
+// (C) Copyright John maddock 1999. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for documentation
+
+#ifndef BOOST_VERSION_HPP
+#define BOOST_VERSION_HPP
+
+//
+// Caution: this is the only Boost header that is guaranteed
+// to change with every Boost release. Including this header
+// will cause a recompile every time a new Boost version is
+// used.
+//
+// BOOST_VERSION % 100 is the patch level
+// BOOST_VERSION / 100 % 1000 is the minor version
+// BOOST_VERSION / 100000 is the major version
+
+#define BOOST_VERSION 1070042
+
+//
+// BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
+// but as a *string* in the form "x_y[_z]" where x is the major version
+// number, y is the minor version number, and z is the patch level if not 0.
+// This is used by <config/auto_link.hpp> to select which library version to
+// link to.
+
+#define BOOST_LIB_VERSION "1_70_42"
+
+#endif
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfig.cmake
new file mode 100644
index 000000000..97d4c797b
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfig.cmake
@@ -0,0 +1,7 @@
+# Don't have targets
+set(Boost_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include")
+
+set(Boost_DATE_TIME_FOUND 1)
+set(Boost_DATE_TIME_LIBRARY "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_date_time.a")
+
+set(Boost_LIBRARIES ${Boost_DATE_TIME_LIBRARY})
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfigVersion.cmake b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfigVersion.cmake
new file mode 100644
index 000000000..b4b606000
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.70.42)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 70 AND PACKAGE_FIND_VERSION_PATCH EQUAL 42)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include/boost/version.hpp b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include/boost/version.hpp
new file mode 100644
index 000000000..fe8e72c6d
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include/boost/version.hpp
@@ -0,0 +1,34 @@
+// Boost version.hpp configuration header file
+// ------------------------------//
+
+// (C) Copyright John maddock 1999. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for documentation
+
+#ifndef BOOST_VERSION_HPP
+#define BOOST_VERSION_HPP
+
+//
+// Caution: this is the only Boost header that is guaranteed
+// to change with every Boost release. Including this header
+// will cause a recompile every time a new Boost version is
+// used.
+//
+// BOOST_VERSION % 100 is the patch level
+// BOOST_VERSION / 100 % 1000 is the minor version
+// BOOST_VERSION / 100000 is the major version
+
+#define BOOST_VERSION 1070042
+
+//
+// BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
+// but as a *string* in the form "x_y[_z]" where x is the major version
+// number, y is the minor version number, and z is the patch level if not 0.
+// This is used by <config/auto_link.hpp> to select which library version to
+// link to.
+
+#define BOOST_LIB_VERSION "1_70_42"
+
+#endif
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfig.cmake
new file mode 100644
index 000000000..3a88f262a
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfig.cmake
@@ -0,0 +1,24 @@
+add_library(Boost::boost INTERFACE IMPORTED)
+add_library(Boost::headers INTERFACE IMPORTED)
+target_include_directories(Boost::headers INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include")
+
+set(Boost_date_time_FOUND 1)
+add_library(Boost::date_time UNKNOWN IMPORTED)
+set_target_properties(Boost::date_time PROPERTIES
+ IMPORTED_CONFIGURATIONS RELEASE
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_date_time.a"
+ )
+set(Boost_python37_FOUND 1)
+add_library(Boost::python UNKNOWN IMPORTED)
+set_target_properties(Boost::python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python_release.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python.a"
+ )
+set(Boost_mpi_python2_FOUND 1)
+add_library(Boost::mpi_python UNKNOWN IMPORTED)
+set_target_properties(Boost::mpi_python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ )
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfigVersion.cmake b/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfigVersion.cmake
new file mode 100644
index 000000000..b4b606000
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.70.42)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 70 AND PACKAGE_FIND_VERSION_PATCH EQUAL 42)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/include/boost/version.hpp b/Tests/RunCMake/FindBoost/CMakePackage_New/include/boost/version.hpp
new file mode 100644
index 000000000..fe8e72c6d
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/include/boost/version.hpp
@@ -0,0 +1,34 @@
+// Boost version.hpp configuration header file
+// ------------------------------//
+
+// (C) Copyright John maddock 1999. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for documentation
+
+#ifndef BOOST_VERSION_HPP
+#define BOOST_VERSION_HPP
+
+//
+// Caution: this is the only Boost header that is guaranteed
+// to change with every Boost release. Including this header
+// will cause a recompile every time a new Boost version is
+// used.
+//
+// BOOST_VERSION % 100 is the patch level
+// BOOST_VERSION / 100 % 1000 is the minor version
+// BOOST_VERSION / 100000 is the major version
+
+#define BOOST_VERSION 1070042
+
+//
+// BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
+// but as a *string* in the form "x_y[_z]" where x is the major version
+// number, y is the minor version number, and z is the patch level if not 0.
+// This is used by <config/auto_link.hpp> to select which library version to
+// link to.
+
+#define BOOST_LIB_VERSION "1_70_42"
+
+#endif
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_date_time.a b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_date_time.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_date_time.a
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_mpi_python.a b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_mpi_python.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_mpi_python.a
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python.a b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python.a
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python_release.a b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python_release.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python_release.a
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfig.cmake b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfig.cmake
new file mode 100644
index 000000000..ba2269adb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfig.cmake
@@ -0,0 +1,25 @@
+# UPPER_CASE FOUND vars and no header targets
+
+set(Boost_DATE_TIME_FOUND 1)
+add_library(Boost::date_time UNKNOWN IMPORTED)
+set_target_properties(Boost::date_time PROPERTIES
+ IMPORTED_CONFIGURATIONS RELEASE
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_date_time.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/include"
+ )
+set(Boost_PYTHON37_FOUND 1)
+add_library(Boost::python UNKNOWN IMPORTED)
+set_target_properties(Boost::python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python_release.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_python.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/include"
+ )
+set(Boost_MPI_PYTHON2_FOUND 1)
+add_library(Boost::mpi_python UNKNOWN IMPORTED)
+set_target_properties(Boost::mpi_python PROPERTIES
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_LIST_DIR}/lib/libboost_mpi_python.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/include"
+ )
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfigVersion.cmake b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfigVersion.cmake
new file mode 100644
index 000000000..b4b606000
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.70.42)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 70 AND PACKAGE_FIND_VERSION_PATCH EQUAL 42)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/include/boost/version.hpp b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/include/boost/version.hpp
new file mode 100644
index 000000000..fe8e72c6d
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/include/boost/version.hpp
@@ -0,0 +1,34 @@
+// Boost version.hpp configuration header file
+// ------------------------------//
+
+// (C) Copyright John maddock 1999. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for documentation
+
+#ifndef BOOST_VERSION_HPP
+#define BOOST_VERSION_HPP
+
+//
+// Caution: this is the only Boost header that is guaranteed
+// to change with every Boost release. Including this header
+// will cause a recompile every time a new Boost version is
+// used.
+//
+// BOOST_VERSION % 100 is the patch level
+// BOOST_VERSION / 100 % 1000 is the minor version
+// BOOST_VERSION / 100000 is the major version
+
+#define BOOST_VERSION 1070042
+
+//
+// BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
+// but as a *string* in the form "x_y[_z]" where x is the major version
+// number, y is the minor version number, and z is the patch level if not 0.
+// This is used by <config/auto_link.hpp> to select which library version to
+// link to.
+
+#define BOOST_LIB_VERSION "1_70_42"
+
+#endif
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll-build-sub-stderr.txt b/Tests/RunCMake/FindBoost/CommonNotFound-stderr.txt
index 8d98f9deb..8d98f9deb 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll-build-sub-stderr.txt
+++ b/Tests/RunCMake/FindBoost/CommonNotFound-stderr.txt
diff --git a/Tests/RunCMake/FindBoost/CommonNotFound-stdout.txt b/Tests/RunCMake/FindBoost/CommonNotFound-stdout.txt
new file mode 100644
index 000000000..644469e5f
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CommonNotFound-stdout.txt
@@ -0,0 +1 @@
+-- Could NOT find Boost
diff --git a/Tests/RunCMake/FindBoost/CommonNotFound.cmake b/Tests/RunCMake/FindBoost/CommonNotFound.cmake
new file mode 100644
index 000000000..864a54913
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CommonNotFound.cmake
@@ -0,0 +1,2 @@
+# Make sure to use the module mode signature here to not bypass FindBoost
+find_package(Boost 1.80 COMPONENTS timer foobar)
diff --git a/Tests/RunCMake/FindBoost/CommonResults-stdout.txt b/Tests/RunCMake/FindBoost/CommonResults-stdout.txt
new file mode 100644
index 000000000..a560843e0
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CommonResults-stdout.txt
@@ -0,0 +1,13 @@
+-- Found Boost: [^
+]* \(found suitable version "1\.70\.0", minimum required is "1\.60"\) found components: .*timer.*
+-- Boost_FOUND
+-- Boost_VERSION=(107000|1\.70\.0)
+-- Boost_VERSION_MAJOR=1
+-- Boost_VERSION_MINOR=70
+-- Boost_VERSION_PATCH=0
+-- Boost_VERSION_COUNT=3
+-- Boost::headers
+-- Boost::boost
+-- Boost::chrono
+-- Boost::timer
+(-- Boost::system)?
diff --git a/Tests/RunCMake/FindBoost/CommonResults.cmake b/Tests/RunCMake/FindBoost/CommonResults.cmake
new file mode 100644
index 000000000..6876800a5
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/CommonResults.cmake
@@ -0,0 +1,25 @@
+# Make sure to use the module mode signature here to not bypass FindBoost
+find_package(Boost 1.60 COMPONENTS timer MODULE)
+if(Boost_FOUND)
+ message(STATUS "Boost_FOUND")
+endif()
+message(STATUS "Boost_VERSION=${Boost_VERSION}")
+message(STATUS "Boost_VERSION_MAJOR=${Boost_VERSION_MAJOR}")
+message(STATUS "Boost_VERSION_MINOR=${Boost_VERSION_MINOR}")
+message(STATUS "Boost_VERSION_PATCH=${Boost_VERSION_PATCH}")
+message(STATUS "Boost_VERSION_COUNT=${Boost_VERSION_COUNT}")
+if(TARGET Boost::headers)
+ message(STATUS "Boost::headers")
+endif()
+if(TARGET Boost::boost)
+ message(STATUS "Boost::boost")
+endif()
+if(TARGET Boost::chrono)
+ message(STATUS "Boost::chrono")
+endif()
+if(TARGET Boost::timer)
+ message(STATUS "Boost::timer")
+endif()
+if(TARGET Boost::system)
+ message(STATUS "Boost::system")
+endif()
diff --git a/Tests/RunCMake/FindBoost/ConfigMode.cmake b/Tests/RunCMake/FindBoost/ConfigMode.cmake
new file mode 100644
index 000000000..5600658a4
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/ConfigMode.cmake
@@ -0,0 +1,2 @@
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackageFixtures/Boost-1.70.0)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CommonResults.cmake)
diff --git a/Tests/RunCMake/FindBoost/ConfigModeNotFound.cmake b/Tests/RunCMake/FindBoost/ConfigModeNotFound.cmake
new file mode 100644
index 000000000..7e90a3cfc
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/ConfigModeNotFound.cmake
@@ -0,0 +1,2 @@
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackageFixtures/Boost-1.70.0)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CommonNotFound.cmake)
diff --git a/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix-stdout.txt b/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix-stdout.txt
new file mode 100644
index 000000000..a781dce30
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix-stdout.txt
@@ -0,0 +1,34 @@
+-- Found Boost: [^
+]* \(found suitable version "1\.70\.42", minimum required is "1\.70"\) found components: date_time python37 mpi_python2 *
+-- Boost_FOUND: TRUE
+-- Boost_INCLUDE_DIRS: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/include
+-- Boost_LIBRARY_DIRS: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib
+-- Boost_LIBRARIES: boost::date_time;boost::python;boost::mpi_python
+-- Boost_DATE_TIME_FOUND: 1
+-- Boost_DATE_TIME_LIBRARY: boost::date_time
+-- Boost_PYTHON37_FOUND: 1
+-- Boost_PYTHON37_LIBRARY: boost::python
+-- Boost_MPI_PYTHON2_FOUND: 1
+-- Boost_MPI_PYTHON2_LIBRARY: boost::mpi_python
+-- Boost_VERSION_MACRO: 1070042
+-- Boost_VERSION_STRING: 1.70.42
+-- Boost_VERSION: 1.70.42
+-- Boost_LIB_VERSION: 1_70_42
+-- Boost_MAJOR_VERSION: 1
+-- Boost_MINOR_VERSION: 70
+-- Boost_SUBMINOR_VERSION: 42
+-- Boost_INCLUDE_DIR: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/include
+-- Boost_DATE_TIME_LIBRARY_DEBUG: *
+-- Boost_DATE_TIME_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_date_time.a
+-- Boost_PYTHON37_LIBRARY_DEBUG: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_python.a
+-- Boost_PYTHON37_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_python_release.a
+-- Boost_MPI_PYTHON2_LIBRARY_DEBUG: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_mpi_python.a
+-- Boost_MPI_PYTHON2_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_mpi_python.a
diff --git a/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix.cmake b/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix.cmake
new file mode 100644
index 000000000..a398c2d8c
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix.cmake
@@ -0,0 +1,6 @@
+# Use a (made up) modern style BoostConfig that defines all targets
+# as boost::<component> with appropriate properties set
+# No legacy variables defined in the BoostConfig
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackage_LowerCaseTargetPrefix)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/LegacyVars.cmake)
diff --git a/Tests/RunCMake/FindBoost/LegacyVars-NoHeaderTarget.cmake b/Tests/RunCMake/FindBoost/LegacyVars-NoHeaderTarget.cmake
new file mode 100644
index 000000000..edb6dda97
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars-NoHeaderTarget.cmake
@@ -0,0 +1,6 @@
+# Use a (made up?) BoostConfig that defines all targets
+# as Boost::<component> with appropriate properties set
+# But no Boost::headers or Boost::boost target is defined
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackage_NoHeaderTarget)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/LegacyVars.cmake)
diff --git a/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined-stdout.txt b/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined-stdout.txt
new file mode 100644
index 000000000..a4e9c6af1
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined-stdout.txt
@@ -0,0 +1,34 @@
+-- Found Boost: [^
+]* \(found suitable version "1\.70\.42", minimum required is "1\.70"\) found components: date_time python37 mpi_python2 *
+-- Boost_FOUND: TRUE
+-- Boost_INCLUDE_DIRS: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/include
+-- Boost_LIBRARY_DIRS: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib
+-- Boost_LIBRARIES: Boost::date_time;Boost::python;Boost::mpi_python
+-- Boost_DATE_TIME_FOUND: 1
+-- Boost_DATE_TIME_LIBRARY: Boost::date_time
+-- Boost_PYTHON37_FOUND: 1
+-- Boost_PYTHON37_LIBRARY: Boost::python
+-- Boost_MPI_PYTHON2_FOUND: 1
+-- Boost_MPI_PYTHON2_LIBRARY: Boost::mpi_python
+-- Boost_VERSION_MACRO: 1070042
+-- Boost_VERSION_STRING: 1.70.42
+-- Boost_VERSION: 1.70.42
+-- Boost_LIB_VERSION: 1_70_42
+-- Boost_MAJOR_VERSION: 1
+-- Boost_MINOR_VERSION: 70
+-- Boost_SUBMINOR_VERSION: 42
+-- Boost_INCLUDE_DIR: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/include
+-- Boost_DATE_TIME_LIBRARY_DEBUG: *
+-- Boost_DATE_TIME_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_date_time.a
+-- Boost_PYTHON37_LIBRARY_DEBUG: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_python.a
+-- Boost_PYTHON37_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_python_release.a
+-- Boost_MPI_PYTHON2_LIBRARY_DEBUG: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_mpi_python.a
+-- Boost_MPI_PYTHON2_LIBRARY_RELEASE: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage[^/]*/lib/libboost_mpi_python.a
diff --git a/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined.cmake b/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined.cmake
new file mode 100644
index 000000000..19ad49f8f
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined.cmake
@@ -0,0 +1,6 @@
+# Use a modern style BoostConfig that defines all targets
+# as Boost::<component> with appropriate properties set
+# No legacy variables defined in the BoostConfig
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackage_New)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/LegacyVars.cmake)
diff --git a/Tests/RunCMake/FindBoost/LegacyVars.cmake b/Tests/RunCMake/FindBoost/LegacyVars.cmake
new file mode 100644
index 000000000..d0d5ee01c
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/LegacyVars.cmake
@@ -0,0 +1,28 @@
+find_package(Boost 1.70 COMPONENTS date_time python37 mpi_python2)
+
+foreach(var Boost_FOUND Boost_INCLUDE_DIRS Boost_LIBRARY_DIRS Boost_LIBRARIES
+ Boost_DATE_TIME_FOUND Boost_DATE_TIME_LIBRARY
+ Boost_PYTHON37_FOUND Boost_PYTHON37_LIBRARY
+ Boost_MPI_PYTHON2_FOUND Boost_MPI_PYTHON2_LIBRARY
+ Boost_VERSION_MACRO Boost_VERSION_STRING Boost_VERSION Boost_LIB_VERSION
+ Boost_MAJOR_VERSION Boost_MINOR_VERSION Boost_SUBMINOR_VERSION
+)
+ message(STATUS "${var}: ${${var}}")
+endforeach()
+
+foreach(cachevar Boost_INCLUDE_DIR
+ Boost_DATE_TIME_LIBRARY_DEBUG Boost_DATE_TIME_LIBRARY_RELEASE
+ Boost_PYTHON37_LIBRARY_DEBUG Boost_PYTHON37_LIBRARY_RELEASE
+ Boost_MPI_PYTHON2_LIBRARY_DEBUG Boost_MPI_PYTHON2_LIBRARY_RELEASE
+)
+ unset(${cachevar})
+ message(STATUS "${cachevar}: ${${cachevar}}")
+endforeach()
+
+foreach(lib Boost::headers Boost::date_time Boost::python Boost::mpi_python
+ Boost::boost Boost::diagnostic_definitions Boost::disable_autolinking Boost::dynamic_linking
+)
+ if(NOT TARGET ${lib})
+ message(FATAL_ERROR "Missing target ${lib}")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/FindBoost/MissingTarget-stdout.txt b/Tests/RunCMake/FindBoost/MissingTarget-stdout.txt
new file mode 100644
index 000000000..8e9d684c8
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MissingTarget-stdout.txt
@@ -0,0 +1,22 @@
+-- Found Boost: [^
+]* \(found suitable version "1\.70\.42", minimum required is "1\.70"\) found components: date_time *
+-- Boost_FOUND: TRUE
+-- Boost_INCLUDE_DIRS: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include
+-- Boost_LIBRARY_DIRS: *
+-- Boost_LIBRARIES: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/lib/libboost_date_time.a
+-- Boost_DATE_TIME_FOUND: 1
+-- Boost_DATE_TIME_LIBRARY: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/lib/libboost_date_time.a
+-- Boost_VERSION_MACRO: 1070042
+-- Boost_VERSION_STRING: 1.70.42
+-- Boost_VERSION: 1.70.42
+-- Boost_LIB_VERSION: 1_70_42
+-- Boost_MAJOR_VERSION: 1
+-- Boost_MINOR_VERSION: 70
+-- Boost_SUBMINOR_VERSION: 42
+-- Boost_INCLUDE_DIR: [^
+]*/Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include
+-- Boost_DATE_TIME_LIBRARY_DEBUG: *
+-- Boost_DATE_TIME_LIBRARY_RELEASE: *
diff --git a/Tests/RunCMake/FindBoost/MissingTarget.cmake b/Tests/RunCMake/FindBoost/MissingTarget.cmake
new file mode 100644
index 000000000..581e0065f
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MissingTarget.cmake
@@ -0,0 +1,25 @@
+set(Boost_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMakePackage_MissingTarget)
+find_package(Boost 1.70 COMPONENTS date_time)
+
+foreach(var Boost_FOUND Boost_INCLUDE_DIRS Boost_LIBRARY_DIRS Boost_LIBRARIES
+ Boost_DATE_TIME_FOUND Boost_DATE_TIME_LIBRARY
+ Boost_VERSION_MACRO Boost_VERSION_STRING Boost_VERSION Boost_LIB_VERSION
+ Boost_MAJOR_VERSION Boost_MINOR_VERSION Boost_SUBMINOR_VERSION
+)
+ message(STATUS "${var}: ${${var}}")
+endforeach()
+
+foreach(cachevar Boost_INCLUDE_DIR
+ Boost_DATE_TIME_LIBRARY_DEBUG Boost_DATE_TIME_LIBRARY_RELEASE
+)
+ unset(${cachevar})
+ message(STATUS "${cachevar}: ${${cachevar}}")
+endforeach()
+
+foreach(lib Boost::headers
+ Boost::boost Boost::diagnostic_definitions Boost::disable_autolinking Boost::dynamic_linking
+)
+ if(NOT TARGET ${lib})
+ message(FATAL_ERROR "Missing target ${lib}")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/chrono.hpp b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/chrono.hpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/chrono.hpp
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/config.hpp b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/config.hpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/config.hpp
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/system/config.hpp b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/system/config.hpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/system/config.hpp
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/timer.hpp b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/timer.hpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/timer.hpp
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/version.hpp b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/version.hpp
new file mode 100644
index 000000000..3ca02b32a
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/version.hpp
@@ -0,0 +1,34 @@
+// Boost version.hpp configuration header file
+// ------------------------------//
+
+// (C) Copyright John maddock 1999. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for documentation
+
+#ifndef BOOST_VERSION_HPP
+#define BOOST_VERSION_HPP
+
+//
+// Caution: this is the only Boost header that is guaranteed
+// to change with every Boost release. Including this header
+// will cause a recompile every time a new Boost version is
+// used.
+//
+// BOOST_VERSION % 100 is the patch level
+// BOOST_VERSION / 100 % 1000 is the minor version
+// BOOST_VERSION / 100000 is the major version
+
+#define BOOST_VERSION 107000
+
+//
+// BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
+// but as a *string* in the form "x_y[_z]" where x is the major version
+// number, y is the minor version number, and z is the patch level if not 0.
+// This is used by <config/auto_link.hpp> to select which library version to
+// link to.
+
+#define BOOST_LIB_VERSION "1_70"
+
+#endif
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_chrono-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_chrono-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_chrono-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_system-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_system-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_system-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_timer-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_timer-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_timer-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.a b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.a
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.so.1.70.0 b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.so.1.70.0
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.so.1.70.0
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.a b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.a
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.so.1.70.0 b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.so.1.70.0
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.so.1.70.0
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer-mt-1_70.lib b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer-mt-1_70.lib
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer-mt-1_70.lib
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.a b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.a
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.a
diff --git a/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.so.1.70.0 b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.so.1.70.0
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.so.1.70.0
diff --git a/Tests/RunCMake/FindBoost/ModuleMode.cmake b/Tests/RunCMake/FindBoost/ModuleMode.cmake
new file mode 100644
index 000000000..823fc53d4
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/ModuleMode.cmake
@@ -0,0 +1,4 @@
+set(BOOST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MockInstalls/1.70.0)
+set(Boost_NO_BOOST_CMAKE ON)
+set(Boost_NO_SYSTEM_PATHS ON)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CommonResults.cmake)
diff --git a/Tests/RunCMake/FindBoost/ModuleModeNotFound.cmake b/Tests/RunCMake/FindBoost/ModuleModeNotFound.cmake
new file mode 100644
index 000000000..aaffbf2a1
--- /dev/null
+++ b/Tests/RunCMake/FindBoost/ModuleModeNotFound.cmake
@@ -0,0 +1,4 @@
+set(BOOST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MockInstalls/1.70.0)
+set(Boost_NO_BOOST_CMAKE ON)
+set(Boost_NO_SYSTEM_PATHS ON)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CommonNotFound.cmake)
diff --git a/Tests/RunCMake/FindBoost/RunCMakeTest.cmake b/Tests/RunCMake/FindBoost/RunCMakeTest.cmake
index eef350c6c..851a996db 100644
--- a/Tests/RunCMake/FindBoost/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindBoost/RunCMakeTest.cmake
@@ -3,3 +3,26 @@ unset(ENV{Boost_ROOT})
run_cmake(CMakePackage)
run_cmake(NoCXX)
+
+run_cmake(LegacyVars-TargetsDefined) # "Good" BoostConfig
+run_cmake(LegacyVars-LowercaseTargetPrefix)
+set(RunCMake-stdout-file LegacyVars-TargetsDefined-stdout.txt)
+run_cmake(LegacyVars-NoHeaderTarget)
+
+unset(RunCMake-stdout-file)
+run_cmake(MissingTarget)
+
+set(RunCMake-stdout-file CommonResults-stdout.txt)
+run_cmake(ConfigMode)
+run_cmake(ModuleMode)
+unset(RunCMake-stdout-file)
+set(RunCMake-stdout-file CommonNotFound-stdout.txt)
+set(RunCMake-stderr-file CommonNotFound-stderr.txt)
+run_cmake(ConfigModeNotFound)
+run_cmake(ModuleModeNotFound)
+unset(RunCMake-stdout-file)
+unset(RunCMake-stderr-file)
+
+run_cmake(CMP0093-NEW)
+run_cmake(CMP0093-OLD)
+run_cmake(CMP0093-UNSET)
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake
new file mode 100644
index 000000000..f5f5c8cea
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake
@@ -0,0 +1,21 @@
+# Prepare environment and variables
+set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH FALSE)
+if(WIN32)
+ set(ENV{CMAKE_PREFIX_PATH} "C:\\baz")
+ set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}\\pc-bletch\\lib\\pkgconfig;X:\\this\\directory\\should\\not\\exist\\in\\the\\filesystem")
+else()
+ set(ENV{CMAKE_PREFIX_PATH} "/baz")
+ set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/pc-bletch/lib/pkgconfig:/this/directory/should/not/exist/in/the/filesystem")
+endif()
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(BLETCH QUIET bletch)
+
+if (NOT BLETCH_FOUND)
+ message(FATAL_ERROR "Failed to find embedded package bletch via PKG_CONFIG_PATH")
+endif ()
+
+pkg_get_variable(bletchvar bletch jackpot)
+if (NOT bletchvar STREQUAL "bletch-lives")
+ message(FATAL_ERROR "Failed to fetch variable jackpot from embedded package bletch via PKG_CONFIG_PATH")
+endif ()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake
new file mode 100644
index 000000000..cfc0760df
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake
@@ -0,0 +1,21 @@
+# Prepare environment and variables
+set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH TRUE)
+if(WIN32)
+ set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}\\pc-bletch;X:\\this\\directory\\should\\not\\exist\\in\\the\\filesystem")
+ set(ENV{PKG_CONFIG_PATH} "C:\\baz")
+else()
+ set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/pc-bletch:/this/directory/should/not/exist/in/the/filesystem")
+ set(ENV{PKG_CONFIG_PATH} "/baz")
+endif()
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(BLETCH QUIET bletch)
+
+if (NOT BLETCH_FOUND)
+ message(FATAL_ERROR "Failed to find embedded package bletch via CMAKE_PREFIX_PATH")
+endif ()
+
+pkg_get_variable(bletchvar bletch jackpot)
+if (NOT bletchvar STREQUAL "bletch-lives")
+ message(FATAL_ERROR "Failed to fetch variable jackpot from embedded package bletch via CMAKE_PREFIX_PATH")
+endif ()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
index 24e720229..e82b05fd8 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
@@ -109,3 +109,24 @@ pkg_check_modules(FakePackage2 REQUIRED QUIET IMPORTED_TARGET cmakeinternalfakep
if (NOT FakePackage2_LINK_LIBRARIES STREQUAL "${fakePkgDir}/lib/libcmakeinternalfakepackage2.a")
message(FATAL_ERROR "FakePackage2_LINK_LIBRARIES has bad content on second run: ${FakePackage2_LINK_LIBRARIES}")
endif()
+
+set(pname fakelinkoptionspackage)
+file(WRITE ${fakePkgDir}/lib/pkgconfig/${pname}.pc
+"Name: FakeLinkOptionsPackage
+Description: Dummy package for FindPkgConfig IMPORTED_TARGET INTERFACE_LINK_OPTIONS test
+Version: 1.2.3
+Libs: -e dummy_main
+")
+
+set(expected_link_options -e dummy_main)
+pkg_check_modules(FakeLinkOptionsPackage REQUIRED QUIET IMPORTED_TARGET fakelinkoptionspackage)
+if (NOT TARGET PkgConfig::FakeLinkOptionsPackage)
+ message(FATAL_ERROR "No import target for fake link options package")
+endif()
+get_target_property(link_options PkgConfig::FakeLinkOptionsPackage INTERFACE_LINK_OPTIONS)
+if (NOT link_options STREQUAL expected_link_options)
+ message(FATAL_ERROR
+ "Additional link options not present in INTERFACE_LINK_OPTIONS property"
+ "expected: \"${expected_link_options}\", but got \"${link_options}\""
+ )
+endif()
diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
index 671ff518b..414d9b68f 100644
--- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
@@ -14,6 +14,8 @@ endif()
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
run_cmake(FindPkgConfig_GET_VARIABLE)
+ run_cmake(FindPkgConfig_GET_VARIABLE_PREFIX_PATH)
+ run_cmake(FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH)
run_cmake(FindPkgConfig_cache_variables)
run_cmake(FindPkgConfig_IMPORTED_TARGET)
run_cmake(FindPkgConfig_VERSION_OPERATORS)
diff --git a/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc b/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc
new file mode 100644
index 000000000..04d2c1b00
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc
@@ -0,0 +1,12 @@
+prefix=/opt/bletch
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+jackpot=bletch-lives
+
+Name: Bletch
+Description: Dummy packaget to test variable support
+Version: 1.0
+Libs: -L${libdir} -lbletch
+Cflags: -Dbletch_version=1
diff --git a/Tests/RunCMake/Framework/FrameworkLayout.cmake b/Tests/RunCMake/Framework/FrameworkLayout.cmake
index 4f4245952..84012aa36 100644
--- a/Tests/RunCMake/Framework/FrameworkLayout.cmake
+++ b/Tests/RunCMake/Framework/FrameworkLayout.cmake
@@ -11,8 +11,11 @@ add_library(Framework ${FRAMEWORK_TYPE}
flatresource.txt
deepresource.txt
some.txt)
+if("${CMAKE_FRAMEWORK}" STREQUAL "")
+ set_target_properties(Framework PROPERTIES
+ FRAMEWORK TRUE)
+endif()
set_target_properties(Framework PROPERTIES
- FRAMEWORK TRUE
PUBLIC_HEADER foo.h
RESOURCE "res.txt")
set_source_files_properties(flatresource.txt PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
diff --git a/Tests/RunCMake/Framework/RunCMakeTest.cmake b/Tests/RunCMake/Framework/RunCMakeTest.cmake
index e705a31fa..c7e1319c1 100644
--- a/Tests/RunCMake/Framework/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Framework/RunCMakeTest.cmake
@@ -20,11 +20,14 @@ framework_layout_test(iOSFrameworkLayout-build ios STATIC)
framework_layout_test(OSXFrameworkLayout-build osx SHARED)
framework_layout_test(OSXFrameworkLayout-build osx STATIC)
-function(framework_type_test Toolchain Type)
+function(framework_type_test Toolchain Type UseProperty)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${Toolchain}${Type}FrameworkType-build)
set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/${Toolchain}.cmake")
list(APPEND RunCMake_TEST_OPTIONS "-DFRAMEWORK_TYPE=${Type}")
+ if(NOT ${UseProperty})
+ list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_FRAMEWORK=YES")
+ endif()
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
@@ -33,7 +36,12 @@ function(framework_type_test Toolchain Type)
run_cmake_command(FrameworkType${Type}-build ${CMAKE_COMMAND} --build .)
endfunction()
-framework_type_test(ios SHARED)
-framework_type_test(ios STATIC)
-framework_type_test(osx SHARED)
-framework_type_test(osx STATIC)
+framework_type_test(ios SHARED NO)
+framework_type_test(ios STATIC NO)
+framework_type_test(osx SHARED NO)
+framework_type_test(osx STATIC NO)
+
+framework_type_test(ios SHARED YES)
+framework_type_test(ios STATIC YES)
+framework_type_test(osx SHARED YES)
+framework_type_test(osx STATIC YES)
diff --git a/Tests/RunCMake/GenerateExportHeader/GEH.cmake b/Tests/RunCMake/GenerateExportHeader/GEH.cmake
index ae9a84c43..b3f1c7f53 100644
--- a/Tests/RunCMake/GenerateExportHeader/GEH.cmake
+++ b/Tests/RunCMake/GenerateExportHeader/GEH.cmake
@@ -51,6 +51,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
set(CMAKE_CXX_STANDARD 11)
endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
add_subdirectory(lib_shared_and_static)
if(CMAKE_SYSTEM_NAME MATCHES "AIX" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
diff --git a/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt
index 0e48ba423..86d3e0472 100644
--- a/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt
@@ -50,4 +50,6 @@ CMake Error at BadAND.cmake:1 \(add_custom_target\):
Parameters to \$<AND> must resolve to either '0' or '1'.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
index 964ea4d4e..42dd0ce50 100644
--- a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
@@ -32,4 +32,6 @@ CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
Expression syntax not recognized.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt
index e5e628c30..627327c12 100644
--- a/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt
@@ -49,4 +49,6 @@ CMake Error at BadNOT.cmake:1 \(add_custom_target\):
\$<NOT> parameter must resolve to exactly one '0' or '1' value.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt
index eb263286e..56e6af00f 100644
--- a/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt
@@ -50,4 +50,6 @@ CMake Error at BadOR.cmake:1 \(add_custom_target\):
Parameters to \$<OR> must resolve to either '0' or '1'.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
index 8d3c4ccd6..a08e7b236 100644
--- a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
@@ -15,3 +15,12 @@ CMake Error at BadSHELL_PATH.cmake:[0-9]+ \(add_custom_target\):
"Relative/Path" is not an absolute path.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
++
+CMake Error at BadSHELL_PATH.cmake:[0-9]+ \(add_custom_target\):
+ Error evaluating generator expression:
+
+ \$<SHELL_PATH:;>
+
+ "" is not an absolute path.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
index 5eff7bccb..0e7c342e4 100644
--- a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
+++ b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
@@ -1,4 +1,5 @@
add_custom_target(check ALL COMMAND check
$<SHELL_PATH:>
$<SHELL_PATH:Relative/Path>
+ "$<SHELL_PATH:;>"
VERBATIM)
diff --git a/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt
index dd0d931be..2f04c78f0 100644
--- a/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt
@@ -35,4 +35,6 @@ CMake Error at BadStrEqual.cmake:1 \(add_custom_target\):
\$<STREQUAL> expression requires 2 comma separated parameters, but got 3
instead.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt
index 969393acc..98eed1f0a 100644
--- a/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt
@@ -5,4 +5,6 @@ CMake Error at BadTargetName.cmake:1 \(add_custom_target\):
\$<TARGET_NAME> expression requires literal input.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:3 \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt
new file mode 100644
index 000000000..2ee96ed14
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at COMPILE_LANG_AND_ID-add_custom_command.cmake:2 \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID>
+
+ \$<COMPILE_LANG_AND_ID> expression requires at least two parameters.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command.cmake
new file mode 100644
index 000000000..9bd5e8e7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command.cmake
@@ -0,0 +1,4 @@
+add_custom_target(drive)
+add_custom_command(TARGET drive PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANG_AND_ID>
+)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-stderr.txt
new file mode 100644
index 000000000..589e64b4e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at COMPILE_LANG_AND_ID-add_custom_target.cmake:2 \(add_custom_target\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID:LANG,ID>
+
+ \$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets to
+ specify include directories, compile definitions, and compile options. It
+ may not be used with the add_custom_command, add_custom_target, or
+ file\(GENERATE\) commands.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target.cmake
new file mode 100644
index 000000000..398db1978
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_target.cmake
@@ -0,0 +1,4 @@
+
+add_custom_target(drive
+ COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANG_AND_ID:LANG,ID>
+)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-stderr.txt
new file mode 100644
index 000000000..3b3f38d37
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at COMPILE_LANG_AND_ID-add_executable.cmake:1 \(add_executable\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID:C,MSVC>
+
+ \$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets to
+ specify include directories, compile definitions, and compile options. It
+ may not be used with the add_custom_command, add_custom_target, or
+ file\(GENERATE\) commands.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable.cmake
new file mode 100644
index 000000000..2245f5046
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_executable.cmake
@@ -0,0 +1,5 @@
+add_executable(empty main.c
+ $<$<COMPILE_LANG_AND_ID:C,MSVC>:empty.c>
+ $<$<COMPILE_LANG_AND_ID:C,GNU>:empty2.c>
+ $<$<COMPILE_LANG_AND_ID:C,Clang>:empty3.c>
+ )
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-stderr.txt
new file mode 100644
index 000000000..4cbf000ea
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at COMPILE_LANG_AND_ID-add_library.cmake:2 \(add_library\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID:C,MSVC>
+
+ \$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets to
+ specify include directories, compile definitions, and compile options. It
+ may not be used with the add_custom_command, add_custom_target, or
+ file\(GENERATE\) commands.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library.cmake
new file mode 100644
index 000000000..044962a53
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_library.cmake
@@ -0,0 +1,2 @@
+
+add_library(empty empty.$<COMPILE_LANG_AND_ID:C,MSVC>)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-stderr.txt
new file mode 100644
index 000000000..26a5940f3
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at COMPILE_LANG_AND_ID-add_test.cmake:5 \(add_test\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID:CXX,GNU>
+
+ \$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets to
+ specify include directories, compile definitions, and compile options. It
+ may not be used with the add_custom_command, add_custom_target, or
+ file\(GENERATE\) commands.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test.cmake
new file mode 100644
index 000000000..b5b6c2b82
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_test.cmake
@@ -0,0 +1,5 @@
+
+include(CTest)
+enable_testing()
+
+add_test(NAME dummy COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_LANG_AND_ID:CXX,GNU>)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-stderr.txt
new file mode 100644
index 000000000..0c4ecd091
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID:C,MSVC>
+
+ \$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets to
+ specify include directories, compile definitions, and compile options. It
+ may not be used with the add_custom_command, add_custom_target, or
+ file\(GENERATE\) commands.
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install.cmake
new file mode 100644
index 000000000..c13eda6ec
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-install.cmake
@@ -0,0 +1,5 @@
+
+install(FILES
+ empty.$<COMPILE_LANG_AND_ID:C,MSVC>
+ DESTINATION src
+)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-stderr.txt
new file mode 100644
index 000000000..3ecbdc360
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at COMPILE_LANG_AND_ID-target_sources.cmake:2 \(target_sources\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_LANG_AND_ID>
+
+ \$<COMPILE_LANG_AND_ID> expression requires at least two parameters.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources.cmake
new file mode 100644
index 000000000..a2c9b03f5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources.cmake
@@ -0,0 +1,2 @@
+add_library(empty)
+target_sources(empty PRIVATE empty.$<COMPILE_LANG_AND_ID>)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-unknown-lang.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-unknown-lang.cmake
new file mode 100644
index 000000000..b9e840b41
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-unknown-lang.cmake
@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_compile_options(empty PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,GNU>:$<TARGET_EXISTS:too,many,parameters>>)
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake
new file mode 100644
index 000000000..605ae4d19
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "DO_NOT_FILTER_THIS;thisisanitem")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake
new file mode 100644
index 000000000..b879be220
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake
@@ -0,0 +1,4 @@
+cmake_policy(VERSION 3.11)
+
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},EXCLUDE,^FILTER_THIS_.+>")
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake
new file mode 100644
index 000000000..9d48d982a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "FILTER_THIS_BIT;FILTER_THIS_THING")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake
new file mode 100644
index 000000000..5e0260ad7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake
@@ -0,0 +1,4 @@
+cmake_policy(VERSION 3.11)
+
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},INCLUDE,^FILTER_THIS_.+>")
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt
new file mode 100644
index 000000000..dd1092556
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at FILTER-InvalidOperator.cmake:3 \(file\):
+ Error evaluating generator expression:
+
+ \$<FILTER:,RM,>
+
+ \$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake
new file mode 100644
index 000000000..26f3917dc
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,RM,>")
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake
new file mode 100644
index 000000000..2844484c5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake
new file mode 100644
index 000000000..e0fc671d0
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,INCLUDE,>")
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-result.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt
new file mode 100644
index 000000000..3b2a814a7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake:2 \(add_custom_target\):
+ Error evaluating generator expression:
+
+ \$<TARGET_PDB_FILE_BASE_NAME:empty>
+
+ TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake
new file mode 100644
index 000000000..489d8e620
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake
@@ -0,0 +1,2 @@
+add_library(empty UNKNOWN IMPORTED)
+add_custom_target(custom COMMAND echo $<TARGET_PDB_FILE_BASE_NAME:empty>)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-stderr.txt
new file mode 100644
index 000000000..b061ce3de
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake:6 \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_PDB_FILE_BASE_NAME:empty>
+
+ TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake
new file mode 100644
index 000000000..811c3f70f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_PDB_FILE_BASE_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt
new file mode 100644
index 000000000..c7d245c54
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake:6 \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_PDB_FILE_BASE_NAME:empty>
+
+ TARGET_PDB_FILE_BASE_NAME is allowed only for targets with linker created
+ artifacts.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake
new file mode 100644
index 000000000..811c3f70f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_PDB_FILE_BASE_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
index bf592e75c..013c4f25b 100644
--- a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
@@ -1,4 +1,10 @@
CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
- Target 'empty1' OUTPUT_NAME depends on itself.
+ Target 'empty2' OUTPUT_NAME depends on itself.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+
+
+CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
+ Target 'empty2' OUTPUT_NAME depends on itself.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
index 5cb80509e..006b0daad 100644
--- a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
@@ -1,3 +1,6 @@
enable_language(C)
add_executable(empty1 empty.c)
set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>)
+
+add_executable(empty2 empty.c)
+set_property(TARGET empty2 PROPERTY OUTPUT_NAME $<TARGET_FILE_BASE_NAME:empty2>)
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake
new file mode 100644
index 000000000..e127711eb
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "1")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake
new file mode 100644
index 000000000..53934afb0
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake
new file mode 100644
index 000000000..e127711eb
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "1")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake
new file mode 100644
index 000000000..a8aca6e35
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:1$<SEMICOLON>1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake
new file mode 100644
index 000000000..e3055ce94
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "2;1")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake
new file mode 100644
index 000000000..ee2dd3ea5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:2$<SEMICOLON>1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake
new file mode 100644
index 000000000..e3055ce94
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "2;1")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake
new file mode 100644
index 000000000..557bc28c1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:2$<SEMICOLON>1$<SEMICOLON>2>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake
new file mode 100644
index 000000000..f779d489b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "")
+if(NOT content STREQUAL expected)
+ set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake
new file mode 100644
index 000000000..3b9d674ff
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:>")
diff --git a/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake b/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake
new file mode 100644
index 000000000..722ae0527
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake
@@ -0,0 +1,6 @@
+
+function (CHECK_VALUE test_msg value expected)
+ if (NOT value STREQUAL expected)
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [[${value}]]\nbut expected:\n [[${expected}]]\n")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 8a5604c7a..68a017251 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -31,8 +31,29 @@ run_cmake(COMPILE_LANGUAGE-add_executable)
run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang)
+run_cmake(COMPILE_LANG_AND_ID-add_custom_target)
+run_cmake(COMPILE_LANG_AND_ID-add_custom_command)
+run_cmake(COMPILE_LANG_AND_ID-install)
+run_cmake(COMPILE_LANG_AND_ID-target_sources)
+run_cmake(COMPILE_LANG_AND_ID-add_executable)
+run_cmake(COMPILE_LANG_AND_ID-add_library)
+run_cmake(COMPILE_LANG_AND_ID-add_test)
+run_cmake(COMPILE_LANG_AND_ID-unknown-lang)
run_cmake(TARGET_FILE-recursion)
run_cmake(OUTPUT_NAME-recursion)
+run_cmake(TARGET_FILE_PREFIX)
+run_cmake(TARGET_FILE_PREFIX-imported-target)
+run_cmake(TARGET_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_FILE_SUFFIX)
+run_cmake(TARGET_FILE_SUFFIX-imported-target)
+run_cmake(TARGET_FILE_SUFFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_SUFFIX-non-valid-target)
+run_cmake_with_options(TARGET_FILE_BASE_NAME -DCMAKE_BUILD_TYPE:STRING=Debug)
+run_cmake_with_options(TARGET_FILE_BASE_NAME-imported-target -DCMAKE_BUILD_TYPE:STRING=Debug)
+run_cmake(TARGET_FILE_BASE_NAME-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_BASE_NAME-non-valid-target)
+run_cmake(TARGET_PROPERTY-INCLUDE_DIRECTORIES)
run_cmake(TARGET_PROPERTY-LOCATION)
run_cmake(TARGET_PROPERTY-SOURCES)
run_cmake(LINK_ONLY-not-linking)
@@ -53,15 +74,28 @@ run_cmake(TARGET_GENEX_EVAL)
run_cmake(GENEX_EVAL-recursion1)
run_cmake(GENEX_EVAL-recursion2)
run_cmake(GENEX_EVAL)
+run_cmake(REMOVE_DUPLICATES-empty)
+run_cmake(REMOVE_DUPLICATES-1)
+run_cmake(REMOVE_DUPLICATES-2)
+run_cmake(REMOVE_DUPLICATES-3)
+run_cmake(REMOVE_DUPLICATES-4)
+run_cmake(FILTER-empty)
+run_cmake(FILTER-InvalidOperator)
+run_cmake(FILTER-Exclude)
+run_cmake(FILTER-Include)
run_cmake(ImportedTarget-TARGET_BUNDLE_DIR)
run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR)
run_cmake(ImportedTarget-TARGET_PDB_FILE)
+run_cmake(ImportedTarget-TARGET_PDB_FILE_BASE_NAME)
if(LINKER_SUPPORTS_PDB)
run_cmake(NonValidTarget-TARGET_PDB_FILE)
run_cmake(ValidTarget-TARGET_PDB_FILE)
+ run_cmake(NonValidTarget-TARGET_PDB_FILE_BASE_NAME)
+ run_cmake(ValidTarget-TARGET_PDB_FILE_BASE_NAME)
else()
run_cmake(NonValidCompiler-TARGET_PDB_FILE)
+ run_cmake(NonValidCompiler-TARGET_PDB_FILE_BASE_NAME)
endif()
set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=OLD)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-check.cmake
new file mode 100644
index 000000000..793edb1de
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target-check.cmake
new file mode 100644
index 000000000..793edb1de
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake
new file mode 100644
index 000000000..40f7c66f2
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake
@@ -0,0 +1,106 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable(exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable default" "$<TARGET_FILE_BASE_NAME:exec1>" "exec1")
+check_value ("TARGET_FILE_BASE_NAME shared default" "$<TARGET_FILE_BASE_NAME:shared1>" "shared1")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker default" "$<TARGET_LINKER_FILE_BASE_NAME:shared1>" "shared1")
+check_value ("TARGET_FILE_BASE_NAME static default" "$<TARGET_FILE_BASE_NAME:static1>" "static1")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker default" "$<TARGET_LINKER_FILE_BASE_NAME:static1>" "static1")
+]])
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY OUTPUT_NAME exec2_custom)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY OUTPUT_NAME shared2_custom)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY OUTPUT_NAME static2_custom)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable custom" "$<TARGET_FILE_BASE_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_FILE_BASE_NAME shared custom" "$<TARGET_FILE_BASE_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker custom" "$<TARGET_LINKER_FILE_BASE_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_FILE_BASE_NAME static custom" "$<TARGET_FILE_BASE_NAME:static2>" "static2_custom")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker custom" "$<TARGET_LINKER_FILE_BASE_NAME:static2>" "static2_custom")
+]])
+
+
+add_executable (exec3 IMPORTED)
+set_property (TARGET exec3 PROPERTY RUNTIME_OUTPUT_NAME exec3_runtime)
+set_property (TARGET exec3 PROPERTY LIBRARY_OUTPUT_NAME exec3_library)
+set_property (TARGET exec3 PROPERTY ARCHIVE_OUTPUT_NAME exec3_archive)
+add_library (shared3 SHARED IMPORTED)
+set_property (TARGET shared3 PROPERTY RUNTIME_OUTPUT_NAME shared3_runtime)
+set_property (TARGET shared3 PROPERTY LIBRARY_OUTPUT_NAME shared3_library)
+set_property (TARGET shared3 PROPERTY ARCHIVE_OUTPUT_NAME shared3_archive)
+add_library (static3 STATIC IMPORTED)
+set_property (TARGET static3 PROPERTY RUNTIME_OUTPUT_NAME static3_runtime)
+set_property (TARGET static3 PROPERTY LIBRARY_OUTPUT_NAME static3_library)
+set_property (TARGET static3 PROPERTY ARCHIVE_OUTPUT_NAME static3_archive)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable all properties" "$<TARGET_FILE_BASE_NAME:exec3>" "exec3_runtime")
+check_value ("TARGET_FILE_BASE_NAME shared all properties" "$<TARGET_FILE_BASE_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_runtime,shared3_library>")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties" "$<TARGET_LINKER_FILE_BASE_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_archive,shared3_library>")
+check_value ("TARGET_FILE_BASE_NAME static all properties" "$<TARGET_FILE_BASE_NAME:static3>" "static3_archive")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties" "$<TARGET_LINKER_FILE_BASE_NAME:static3>" "static3_archive")
+]])
+
+
+unset(GENERATE_CONDITION)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+ set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+else()
+ set (FIRST_CONFIG ${CMAKE_BUILD_TYPE})
+endif()
+string (TOUPPER "${FIRST_CONFIG}" FIRST_CONFIG)
+
+
+add_executable (exec4 IMPORTED)
+set_property (TARGET exec4 PROPERTY RUNTIME_OUTPUT_NAME exec4_runtime)
+set_property (TARGET exec4 PROPERTY LIBRARY_OUTPUT_NAME exec4_library)
+set_property (TARGET exec4 PROPERTY ARCHIVE_OUTPUT_NAME exec4_archive)
+set_property (TARGET exec4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+add_library (shared4 SHARED IMPORTED)
+set_property (TARGET shared4 PROPERTY RUNTIME_OUTPUT_NAME shared4_runtime)
+set_property (TARGET shared4 PROPERTY LIBRARY_OUTPUT_NAME shared4_library)
+set_property (TARGET shared4 PROPERTY ARCHIVE_OUTPUT_NAME shared4_archive)
+set_property (TARGET shared4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+add_library (static4 STATIC IMPORTED)
+set_property (TARGET static4 PROPERTY RUNTIME_OUTPUT_NAME static4_runtime)
+set_property (TARGET static4 PROPERTY LIBRARY_OUTPUT_NAME static4_library)
+set_property (TARGET static4 PROPERTY ARCHIVE_OUTPUT_NAME static4_archive)
+set_property (TARGET static4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable all properties + postfix" "$<TARGET_FILE_BASE_NAME:exec4>" "exec4_runtime_postfix")
+check_value ("TARGET_FILE_BASE_NAME shared all properties + postfix" "$<TARGET_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_runtime,shared4_library>_postfix")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_archive,shared4_library>_postfix")
+check_value ("TARGET_FILE_BASE_NAME static all properties + postfix" "$<TARGET_FILE_BASE_NAME:static4>" "static4_archive_postfix")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:static4>" "static4_archive_postfix")
+]])
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION})
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-stderr.txt
new file mode 100644
index 000000000..ecb9e5d03
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_BASE_NAME-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_FILE_BASE_NAME:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target.cmake
new file mode 100644
index 000000000..8622b7dc9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_FILE_BASE_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake
new file mode 100644
index 000000000..f88d7109a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake
@@ -0,0 +1,135 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable default" "$<TARGET_FILE_BASE_NAME:exec1>" "exec1")
+check_value ("TARGET_FILE_BASE_NAME shared default" "$<TARGET_FILE_BASE_NAME:shared1>" "shared1")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker default" "$<TARGET_LINKER_FILE_BASE_NAME:shared1>" "shared1")
+check_value ("TARGET_FILE_BASE_NAME static default" "$<TARGET_FILE_BASE_NAME:static1>" "static1")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker default" "$<TARGET_LINKER_FILE_BASE_NAME:static1>" "static1")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+ string(APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_FILE_BASE_NAME executable PDB default" "$<TARGET_PDB_FILE_BASE_NAME:exec1>" "exec1")
+check_value ("TARGET_PDB_FILE_BASE_NAME shared PDB default" "$<TARGET_PDB_FILE_BASE_NAME:shared1>" "shared1")
+]])
+endif()
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY OUTPUT_NAME exec2_custom)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY OUTPUT_NAME shared2_custom)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY OUTPUT_NAME static2_custom)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable custom" "$<TARGET_FILE_BASE_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_FILE_BASE_NAME shared custom" "$<TARGET_FILE_BASE_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker custom" "$<TARGET_LINKER_FILE_BASE_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_FILE_BASE_NAME static custom" "$<TARGET_FILE_BASE_NAME:static2>" "static2_custom")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker custom" "$<TARGET_LINKER_FILE_BASE_NAME:static2>" "static2_custom")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+ string (APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_FILE_BASE_NAME executable PDB custom" "$<TARGET_PDB_FILE_BASE_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_PDB_FILE_BASE_NAME shared PDB custom" "$<TARGET_PDB_FILE_BASE_NAME:shared2>" "shared2_custom")
+ ]])
+endif()
+
+add_executable (exec3 empty.c)
+set_property (TARGET exec3 PROPERTY RUNTIME_OUTPUT_NAME exec3_runtime)
+set_property (TARGET exec3 PROPERTY LIBRARY_OUTPUT_NAME exec3_library)
+set_property (TARGET exec3 PROPERTY ARCHIVE_OUTPUT_NAME exec3_archive)
+set_property (TARGET exec3 PROPERTY PDB_NAME exec3_pdb)
+add_library (shared3 SHARED empty.c)
+set_property (TARGET shared3 PROPERTY RUNTIME_OUTPUT_NAME shared3_runtime)
+set_property (TARGET shared3 PROPERTY LIBRARY_OUTPUT_NAME shared3_library)
+set_property (TARGET shared3 PROPERTY ARCHIVE_OUTPUT_NAME shared3_archive)
+set_property (TARGET shared3 PROPERTY PDB_NAME shared3_pdb)
+add_library (static3 STATIC empty.c)
+set_property (TARGET static3 PROPERTY RUNTIME_OUTPUT_NAME static3_runtime)
+set_property (TARGET static3 PROPERTY LIBRARY_OUTPUT_NAME static3_library)
+set_property (TARGET static3 PROPERTY ARCHIVE_OUTPUT_NAME static3_archive)
+set_property (TARGET static3 PROPERTY PDB_NAME static3_pdb)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable all properties" "$<TARGET_FILE_BASE_NAME:exec3>" "exec3_runtime")
+check_value ("TARGET_FILE_BASE_NAME shared all properties" "$<TARGET_FILE_BASE_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_runtime,shared3_library>")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties" "$<TARGET_LINKER_FILE_BASE_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_archive,shared3_library>")
+check_value ("TARGET_FILE_BASE_NAME static all properties" "$<TARGET_FILE_BASE_NAME:static3>" "static3_archive")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties" "$<TARGET_LINKER_FILE_BASE_NAME:static3>" "static3_archive")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+ string (APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_FILE_BASE_NAME executable PDB all properties" "$<TARGET_PDB_FILE_BASE_NAME:exec3>" "exec3_pdb")
+check_value ("TARGET_PDB_FILE_BASE_NAME shared PDB all properties" "$<TARGET_PDB_FILE_BASE_NAME:shared3>" "shared3_pdb")
+]])
+endif()
+
+
+unset(GENERATE_CONDITION)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+ set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+else()
+ set (FIRST_CONFIG ${CMAKE_BUILD_TYPE})
+endif()
+string (TOUPPER "${FIRST_CONFIG}" FIRST_CONFIG)
+
+
+add_executable (exec4 empty.c)
+set_property (TARGET exec4 PROPERTY RUNTIME_OUTPUT_NAME exec4_runtime)
+set_property (TARGET exec4 PROPERTY LIBRARY_OUTPUT_NAME exec4_library)
+set_property (TARGET exec4 PROPERTY ARCHIVE_OUTPUT_NAME exec4_archive)
+set_property (TARGET exec4 PROPERTY PDB_NAME exec4_pdb)
+set_property (TARGET exec4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+add_library (shared4 SHARED empty.c)
+set_property (TARGET shared4 PROPERTY RUNTIME_OUTPUT_NAME shared4_runtime)
+set_property (TARGET shared4 PROPERTY LIBRARY_OUTPUT_NAME shared4_library)
+set_property (TARGET shared4 PROPERTY ARCHIVE_OUTPUT_NAME shared4_archive)
+set_property (TARGET shared4 PROPERTY PDB_NAME shared4_pdb)
+set_property (TARGET shared4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+add_library (static4 STATIC empty.c)
+set_property (TARGET static4 PROPERTY RUNTIME_OUTPUT_NAME static4_runtime)
+set_property (TARGET static4 PROPERTY LIBRARY_OUTPUT_NAME static4_library)
+set_property (TARGET static4 PROPERTY ARCHIVE_OUTPUT_NAME static4_archive)
+set_property (TARGET static4 PROPERTY PDB_NAME static4_pdb)
+set_property (TARGET static4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_FILE_BASE_NAME executable all properties + postfix" "$<TARGET_FILE_BASE_NAME:exec4>" "exec4_runtime_postfix")
+check_value ("TARGET_FILE_BASE_NAME shared all properties + postfix" "$<TARGET_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_runtime,shared4_library>_postfix")
+check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_archive,shared4_library>_postfix")
+check_value ("TARGET_FILE_BASE_NAME static all properties + postfix" "$<TARGET_FILE_BASE_NAME:static4>" "static4_archive_postfix")
+check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:static4>" "static4_archive_postfix")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+ string (APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_FILE_BASE_NAME executable PDB all properties + postfix" "$<TARGET_PDB_FILE_BASE_NAME:exec4>" "exec4_pdb_postfix")
+check_value ("TARGET_PDB_FILE_BASE_NAME shared PDB all properties + postfix" "$<TARGET_PDB_FILE_BASE_NAME:shared4>" "shared4_pdb_postfix")
+]])
+endif()
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION})
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
new file mode 100644
index 000000000..676ad4bc8
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
new file mode 100644
index 000000000..676ad4bc8
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
new file mode 100644
index 000000000..34e500ac4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable(exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 000000000..81362ef04
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_FILE_PREFIX:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 000000000..d1095fa53
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
new file mode 100644
index 000000000..6bb1e44d6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
new file mode 100644
index 000000000..f159370d7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
new file mode 100644
index 000000000..f159370d7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
new file mode 100644
index 000000000..e1b7654ce
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable (exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 000000000..9ea09d163
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_FILE_SUFFIX:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 000000000..f7089f947
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
new file mode 100644
index 000000000..78afecdaa
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-stderr.txt
new file mode 100644
index 000000000..1ae2f2c86
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_LINKER_FILE_BASE_NAME:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake
new file mode 100644
index 000000000..776fb4bbb
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_LINKER_FILE_BASE_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 000000000..7a36cefbc
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_LINKER_FILE_PREFIX:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 000000000..8dad4dad4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_LINKER_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 000000000..cc5217a14
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_LINKER_FILE_SUFFIX:empty>
+
+ Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 000000000..82c2f3a04
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_LINKER_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
new file mode 100644
index 000000000..cb6f4d867
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.14)
+enable_language(C)
+
+add_library(foo1 STATIC empty.c)
+target_include_directories(foo1 PUBLIC include)
+target_link_libraries(foo1 PRIVATE foo2 foo3 foo4)
+
+add_library(foo2 STATIC empty.c)
+target_include_directories(foo2 PUBLIC $<TARGET_PROPERTY:foo1,INCLUDE_DIRECTORIES>)
+
+add_library(foo3 STATIC empty.c)
+target_include_directories(foo3 PUBLIC $<TARGET_PROPERTY:foo2,INCLUDE_DIRECTORIES>)
+
+add_library(foo4 STATIC empty.c)
+target_include_directories(foo4 PUBLIC $<TARGET_PROPERTY:foo3,INCLUDE_DIRECTORIES>)
+
+# Evaluate a genex that looks up INCLUDE_DIRECTORIES on multiple targets.
+file(GENERATE OUTPUT out.txt CONTENT "$<TARGET_PROPERTY:foo4,INCLUDE_DIRECTORIES>")
diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME-check.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME-check.cmake
new file mode 100644
index 000000000..996d2d4e6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME-check.cmake
@@ -0,0 +1,7 @@
+file(STRINGS ${RunCMake_TEST_BINARY_DIR}/test.txt TEST_TXT ENCODING UTF-8)
+
+list(GET TEST_TXT 0 PDB_FILE_BASE_NAME)
+
+if(NOT PDB_FILE_BASE_NAME MATCHES "empty")
+ set(RunCMake_TEST_FAILED "unexpected PDB_FILE_BASE_NAME [${PDB_FILE_BASE_NAME}]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake
new file mode 100644
index 000000000..cc53bdf0a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake
@@ -0,0 +1,16 @@
+
+enable_language(C)
+
+add_library(empty SHARED empty.c)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+ set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+endif()
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "$<TARGET_PDB_FILE_BASE_NAME:empty>"
+ ${GENERATE_CONDITION}
+)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt
new file mode 100644
index 000000000..9afa461de
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error in CMakeLists.txt:
+ MSVC_RUNTIME_LIBRARY value 'BogusValue' not known for this C compiler.
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake
new file mode 100644
index 000000000..c3ea2fddb
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0091 NEW)
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake
new file mode 100644
index 000000000..734cc9f68
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0091 OLD)
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake
new file mode 100644
index 000000000..26f86a050
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake
new file mode 100644
index 000000000..7827d2a6c
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake
@@ -0,0 +1,37 @@
+enable_language(C)
+
+cmake_policy(GET CMP0091 cmp0091)
+if(cmp0091 STREQUAL "NEW")
+ if(NOT CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT not set under NEW behavior")
+ endif()
+else()
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT is set under OLD behavior")
+ endif()
+endif()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ if(CMAKE_C_FLAGS_DEBUG MATCHES "[/-]MDd( |$)")
+ set(have_MDd 1)
+ else()
+ set(have_MDd 0)
+ endif()
+ if(CMAKE_C_FLAGS_RELEASE MATCHES "[/-]MD( |$)")
+ set(have_MD 1)
+ else()
+ set(have_MD 0)
+ endif()
+ if(cmp0091 STREQUAL "NEW")
+ if(have_MDd OR have_MD)
+ message(SEND_ERROR "Have a -MD* flag under NEW behavior.")
+ endif()
+ else()
+ if(NOT (have_MDd AND have_MD))
+ message(SEND_ERROR "Do not have -MD* flags under OLD behavior.")
+ endif()
+ endif()
+endif()
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY BogusValue)
+add_library(foo empty.c)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt
new file mode 100644
index 000000000..3e470a29c
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake
new file mode 100644
index 000000000..fad18dacc
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0091-WARN)
+run_cmake(CMP0091-OLD)
+run_cmake(CMP0091-NEW)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/empty.c b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake
new file mode 100644
index 000000000..15c52d217
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0092 NEW)
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake
new file mode 100644
index 000000000..ea7544564
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0092 OLD)
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake
new file mode 100644
index 000000000..45e183f4a
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0092-common.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake b/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake
new file mode 100644
index 000000000..87d7f67c6
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+cmake_policy(GET CMP0092 cmp0092)
+if(cmp0092 STREQUAL "NEW")
+ if("${CMAKE_C_FLAGS}" MATCHES "([/-]W[0-9])")
+ message(SEND_ERROR "CMAKE_C_FLAGS has '${CMAKE_MATCH_1}' under NEW behavior")
+ endif()
+else()
+ if(NOT " ${CMAKE_C_FLAGS} " MATCHES " /W3 ")
+ message(SEND_ERROR "CMAKE_C_FLAGS does not have '/W3' under OLD behavior")
+ endif()
+endif()
diff --git a/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt b/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt
new file mode 100644
index 000000000..3e470a29c
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake b/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake
new file mode 100644
index 000000000..7ce448dff
--- /dev/null
+++ b/Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0092-WARN)
+run_cmake(CMP0092-OLD)
+run_cmake(CMP0092-NEW)
diff --git a/Tests/RunCMake/MetaCompileFeatures/C.cmake b/Tests/RunCMake/MetaCompileFeatures/C.cmake
new file mode 100644
index 000000000..3bb6181ab
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/C.cmake
@@ -0,0 +1,27 @@
+
+enable_language(C)
+
+function(check_language_feature_flags lang level)
+ if(CMAKE_${lang}${level}_STANDARD_COMPILE_OPTION)
+ #this property is an internal implementation detail of CMake
+ get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+ list(LENGTH known_features len)
+ if(len LESS 1)
+ message(FATAL_ERROR "unable to find known features of ${lang}${level}")
+ endif()
+
+ string(TOLOWER ${lang} lang_lower)
+ set(known_name ${lang_lower}${level}_known_features)
+ set(meta_name ${lang_lower}${level}_meta_feature)
+
+ add_library(${known_name} STATIC a.c)
+ target_compile_features(${known_name} PUBLIC ${known_features})
+ add_library(${meta_name} STATIC a.c)
+ target_compile_features(${meta_name} PUBLIC ${lang_lower}_std_${level})
+ endif()
+endfunction()
+
+
+check_language_feature_flags(C 90)
+check_language_feature_flags(C 99)
+check_language_feature_flags(C 11)
diff --git a/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt b/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt
new file mode 100644
index 000000000..3e470a29c
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MetaCompileFeatures/CXX.cmake b/Tests/RunCMake/MetaCompileFeatures/CXX.cmake
new file mode 100644
index 000000000..ef3b9d4be
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/CXX.cmake
@@ -0,0 +1,27 @@
+
+enable_language(CXX)
+
+function(check_language_feature_flags lang level)
+ if(CMAKE_${lang}${level}_STANDARD_COMPILE_OPTION)
+ #this property is an internal implementation detail of CMake
+ get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+ list(LENGTH known_features len)
+ if(len LESS 1)
+ message(FATAL_ERROR "unable to find known features of ${lang}${level}")
+ endif()
+
+ string(TOLOWER ${lang} lang_lower)
+ set(known_name ${lang_lower}${level}_known_features)
+ set(meta_name ${lang_lower}${level}_meta_feature)
+
+ add_library(${known_name} STATIC a.cxx)
+ target_compile_features(${known_name} PUBLIC ${known_features})
+ add_library(${meta_name} STATIC a.cxx)
+ target_compile_features(${meta_name} PUBLIC ${lang_lower}_std_${level})
+ endif()
+endfunction()
+
+
+check_language_feature_flags(CXX 98)
+check_language_feature_flags(CXX 11)
+check_language_feature_flags(CXX 14)
diff --git a/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake
new file mode 100644
index 000000000..009cde4f1
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(RunCMake)
+
+run_cmake(C)
+run_cmake(CXX)
diff --git a/Tests/RunCMake/MetaCompileFeatures/a.c b/Tests/RunCMake/MetaCompileFeatures/a.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/a.c
diff --git a/Tests/RunCMake/MetaCompileFeatures/a.cxx b/Tests/RunCMake/MetaCompileFeatures/a.cxx
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/a.cxx
diff --git a/Tests/RunCMake/Ninja/CustomCommandJobPool-check.cmake b/Tests/RunCMake/Ninja/CustomCommandJobPool-check.cmake
new file mode 100644
index 000000000..7f7fa33bf
--- /dev/null
+++ b/Tests/RunCMake/Ninja/CustomCommandJobPool-check.cmake
@@ -0,0 +1,8 @@
+set(log "${RunCMake_BINARY_DIR}/CustomCommandJobPool-build/build.ninja")
+file(READ "${log}" build_file)
+if(NOT "${build_file}" MATCHES "pool = custom_command_pool")
+ set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: pool = custom_command_pool")
+endif()
+if(NOT "${build_file}" MATCHES "pool = custom_target_pool")
+ set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: pool = custom_target_pool")
+endif()
diff --git a/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake b/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake
new file mode 100644
index 000000000..1e36e65e2
--- /dev/null
+++ b/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake
@@ -0,0 +1,17 @@
+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}"
+ JOB_POOL "custom_command_pool"
+ )
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c")
+
+add_custom_target(
+ hello.echo
+ COMMAND echo
+ JOB_POOL "custom_target_pool"
+)
+
+include(CheckNoPrefixSubDir.cmake)
diff --git a/Tests/RunCMake/Ninja/JobPoolUsesTerminal-result.txt b/Tests/RunCMake/Ninja/JobPoolUsesTerminal-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/Ninja/JobPoolUsesTerminal-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Ninja/JobPoolUsesTerminal-stderr.txt b/Tests/RunCMake/Ninja/JobPoolUsesTerminal-stderr.txt
new file mode 100644
index 000000000..45975caeb
--- /dev/null
+++ b/Tests/RunCMake/Ninja/JobPoolUsesTerminal-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at JobPoolUsesTerminal.cmake:1 \(add_custom_command\):
+ add_custom_command JOB_POOL is shadowed by USES_TERMINAL.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at JobPoolUsesTerminal.cmake:2 \(add_custom_target\):
+ add_custom_target JOB_POOL is shadowed by USES_TERMINAL.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/Ninja/JobPoolUsesTerminal.cmake b/Tests/RunCMake/Ninja/JobPoolUsesTerminal.cmake
new file mode 100644
index 000000000..b7e440c60
--- /dev/null
+++ b/Tests/RunCMake/Ninja/JobPoolUsesTerminal.cmake
@@ -0,0 +1,2 @@
+add_custom_command(OUTPUT x COMMAND y USES_TERMINAL JOB_POOL z)
+add_custom_target(CustomTarget COMMAND y USES_TERMINAL JOB_POOL z)
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index 8fa650a61..808a872aa 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -57,6 +57,8 @@ run_CMP0058(NEW-no)
run_CMP0058(NEW-by)
run_cmake(CustomCommandDepfile)
+run_cmake(CustomCommandJobPool)
+run_cmake(JobPoolUsesTerminal)
run_cmake(RspFileC)
run_cmake(RspFileCXX)
diff --git a/Tests/RunCMake/Ninja/greeting.c b/Tests/RunCMake/Ninja/greeting.c
index ba3e55beb..1124d14c0 100644
--- a/Tests/RunCMake/Ninja/greeting.c
+++ b/Tests/RunCMake/Ninja/greeting.c
@@ -6,4 +6,5 @@ __declspec(dllexport)
void greeting(void)
{
printf("Hello world!\n");
+ fflush(stdout);
}
diff --git a/Tests/RunCMake/Ninja/greeting2.c b/Tests/RunCMake/Ninja/greeting2.c
index c6ed87daa..cc8409c11 100644
--- a/Tests/RunCMake/Ninja/greeting2.c
+++ b/Tests/RunCMake/Ninja/greeting2.c
@@ -3,4 +3,5 @@
void greeting2(void)
{
printf("Hello world 2!\n");
+ fflush(stdout);
}
diff --git a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
index 838b3d8c4..4dbd86144 100644
--- a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
+++ b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
@@ -3,6 +3,7 @@ CMake Error at BadSourceExpression3.cmake:2 \(add_library\):
\$<TARGET_OBJECTS:NotObjLib>
- Objects of target "NotObjLib" referenced but is not an OBJECT library.
+ Objects of target "NotObjLib" referenced but is not an allowed library
+ types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake
index c3d9a622d..4e07ea6fa 100644
--- a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake
+++ b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake
@@ -1,2 +1,2 @@
-add_library(NotObjLib STATIC a.c)
+add_library(NotObjLib INTERFACE)
add_library(A STATIC a.c $<TARGET_OBJECTS:NotObjLib>)
diff --git a/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake b/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake
new file mode 100644
index 000000000..0c85c72b0
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake
@@ -0,0 +1,32 @@
+add_library(StaticLib STATIC a.c)
+
+add_custom_command(TARGET StaticLib POST_BUILD
+ VERBATIM
+ COMMAND ${CMAKE_COMMAND}
+ "-DTARGET_OBJECTS=$<TARGET_OBJECTS:StaticLib>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ )
+
+add_library(SharedLib SHARED a.c b.c)
+target_compile_definitions(SharedLib PRIVATE REQUIRED)
+
+add_custom_command(TARGET SharedLib POST_BUILD
+ VERBATIM
+ COMMAND ${CMAKE_COMMAND}
+ "-DTARGET_OBJECTS:STRING=$<TARGET_OBJECTS:SharedLib>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ )
+
+add_executable(ExecObjs a.c b.c exe.c)
+target_compile_definitions(ExecObjs PRIVATE REQUIRED)
+
+add_custom_target(check_exec_objs ALL
+ VERBATIM
+ COMMAND ${CMAKE_COMMAND}
+ "-DTARGET_OBJECTS=$<TARGET_OBJECTS:ExecObjs>"
+ -DEXPECTED_NUM_OBJECTFILES=3
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS ExecObjs
+ )
diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt
index 40d650e21..208f3c9e6 100644
--- a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt
+++ b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt
@@ -2,4 +2,6 @@
The SOURCES of "A" use a generator expression that depends on the SOURCES
themselves.
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
index 6ca33b800..5ec401873 100644
--- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
@@ -37,6 +37,10 @@ function (run_object_lib_build2 name)
run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .)
endfunction ()
+if(NOT (RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]"))
+ run_object_lib_build(CheckTargetObjects)
+endif()
+
run_object_lib_build(LinkObjLHSShared)
run_object_lib_build(LinkObjLHSStatic)
run_object_lib_build(LinkObjRHSShared)
@@ -54,6 +58,7 @@ run_cmake(PostBuild)
run_cmake(PreBuild)
run_cmake(PreLink)
+
function(run_Dependencies)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Dependencies-build)
set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/ObjectLibrary/check_object_files.cmake b/Tests/RunCMake/ObjectLibrary/check_object_files.cmake
new file mode 100644
index 000000000..3c34229ff
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/check_object_files.cmake
@@ -0,0 +1,17 @@
+
+if (NOT TARGET_OBJECTS)
+ message(SEND_ERROR "Object not passed as -DTARGET_OBJECTS")
+endif()
+
+foreach(objlib_file IN LISTS objects)
+ message(STATUS "objlib_file: =${objlib_file}=")
+
+ set(file_exists False)
+ if (EXISTS "${objlib_file}")
+ set(file_exists True)
+ endif()
+
+ if (NOT file_exists)
+ message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake b/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
index a6962642d..5880378c5 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
@@ -10,6 +10,7 @@ project(Minimal NONE)
#
set(targets
aix-C-XL-13.1.3 aix-CXX-XL-13.1.3
+ aix-C-XLClang-16.1.0.1 aix-CXX-XLClang-16.1.0.1
craype-C-Cray-8.7 craype-CXX-Cray-8.7 craype-Fortran-Cray-8.7
craype-C-Cray-9.0-hlist-ad craype-CXX-Cray-9.0-hlist-ad craype-Fortran-Cray-9.0-hlist-ad
craype-C-GNU-7.3.0 craype-CXX-GNU-7.3.0 craype-Fortran-GNU-7.3.0
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt b/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
index b854e2ea2..bffe819a8 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
@@ -12,6 +12,9 @@
#
cmake_minimum_required(VERSION 3.3)
+if(POLICY CMP0089)
+ cmake_policy(SET CMP0089 NEW)
+endif()
set(lngs C CXX)
set(LANGUAGES "${lngs}" CACHE STRING "List of languages to generate inputs for")
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input
new file mode 100644
index 000000000..2f018e624
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input
@@ -0,0 +1,40 @@
+CMAKE_LANG=C
+CMAKE_C_COMPILER_ABI=
+CMAKE_C_COMPILER_AR=
+CMAKE_C_COMPILER_ARCHITECTURE_ID=
+CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_C_COMPILER_ID=XLClang
+CMAKE_C_COMPILER_LAUNCHER=
+CMAKE_C_COMPILER_LOADED=1
+CMAKE_C_COMPILER_RANLIB=
+CMAKE_C_COMPILER_TARGET=
+CMAKE_C_COMPILER_VERSION=16.1.0.1
+CMAKE_C_COMPILER_VERSION_INTERAL=
+Change Dir: /tmp/ii/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/gmake cmTC_fcf21/fast
+/usr/bin/gmake -f CMakeFiles/cmTC_fcf21.dir/build.make CMakeFiles/cmTC_fcf21.dir/build
+gmake[1]: Entering directory '/tmp/ii/CMakeFiles/CMakeTmp'
+Building C object CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o
+/opt/IBM/xlC/16.1.0/bin/xlclang -V -o CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o -c /tmp/CMake/Modules/CMakeCCompilerABI.c
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang
+export XL_ASMOBJFILES=/tmp/xlcASuz87id
+export "XL_DIS=/opt/IBM/xlc/16.1.0/exe/dis -o "CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o" "CMakeCCompilerABI.o""
+/opt/IBM/xlC/16.1.0/exe/xlC2entry -qosvar=aix.7.2 -qalias=ansi -qthreaded -D_THREAD_SAFE -Wno-parentheses -Wno-unused-value -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX50 -D_AIX51 -D_AIX52 -D_AIX53 -D_AIX61 -D_AIX71 -D_AIX72 -D_IBMR2 -D_POWER -xc -qasm_as=/bin/as -qc_stdinc=/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -qvac_include_path=/opt/IBM/xlc/16.1.0/include -oCMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o /tmp/CMake/Modules/CMakeCCompilerABI.c /tmp/xlcW0tZ87ia /tmp/xlcW1ub87ib /dev/null /tmp/xlcLu487ieF.lst /dev/null /tmp/xlcW2uj87ic
+export XL_BACKEND=/opt/IBM/xlc/16.1.0/exe/xlCcode
+export XL_LINKER=/bin/ld
+/opt/IBM/xlc/16.1.0/exe/xlCcode -qalias=ansi -qthreaded /tmp/xlcW0tZ87ia /tmp/xlcW1ub87ib CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o /tmp/xlcLu487ieB.lst /tmp/xlcW2uj87ic
+rm /tmp/xlcASuz87id
+rm /tmp/xlcLu487ie
+rm /tmp/xlcW0tZ87ia
+rm /tmp/xlcW1ub87ib
+rm /tmp/xlcW2uj87ic
+Linking C executable cmTC_fcf21
+/tmp/CMake/bin/cmake -E cmake_link_script CMakeFiles/cmTC_fcf21.dir/link.txt --verbose=1
+/opt/IBM/xlC/16.1.0/bin/xlclang -Wl,-bnoipath -Wl,-brtl -V -Wl,-bexpall CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o -o cmTC_fcf21 -Wl,-blibpath:/usr/lib:/lib
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang
+/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 -bnoipath -brtl -bexpall CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o -o cmTC_fcf21 -blibpath:/usr/lib:/lib -L/opt/IBM/xlmass/9.1.0/lib/aix61 -L/opt/IBM/xlc/16.1.0/lib -lxlopt -lxlipa -lxl -lc -lpthreads
+rm /tmp/xlcW0vJG7ia
+rm /tmp/xlcW1vNG7ib
+rm /tmp/xlcW2vRG7ic
+gmake[1]: Leaving directory '/tmp/ii/CMakeFiles/CMakeTmp'
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output
new file mode 100644
index 000000000..85399b75b
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output
@@ -0,0 +1 @@
+/opt/IBM/xlC/16.1.0/include2;/opt/IBM/xlC/16.1.0/include2/aix;/opt/IBM/xlmass/9.1.0/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input
new file mode 100644
index 000000000..da16db3a0
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input
@@ -0,0 +1,44 @@
+CMAKE_LANG=CXX
+CMAKE_CXX_COMPILER_ABI=
+CMAKE_CXX_COMPILER_AR=
+CMAKE_CXX_COMPILER_ARCHITECTURE_ID=
+CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_CXX_COMPILER_ID=XLClang
+CMAKE_CXX_COMPILER_LAUNCHER=
+CMAKE_CXX_COMPILER_LOADED=1
+CMAKE_CXX_COMPILER_RANLIB=
+CMAKE_CXX_COMPILER_TARGET=
+CMAKE_CXX_COMPILER_VERSION=16.1.0.1
+CMAKE_CXX_COMPILER_VERSION_INTERAL=
+Change Dir: /tmp/ii/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/gmake cmTC_b8490/fast
+/usr/bin/gmake -f CMakeFiles/cmTC_b8490.dir/build.make CMakeFiles/cmTC_b8490.dir/build
+gmake[1]: Entering directory '/tmp/ii/CMakeFiles/CMakeTmp'
+Building CXX object CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o
+/opt/IBM/xlC/16.1.0/bin/xlclang++ -x c++ -V -o CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o -c /tmp/CMake/Modules/CMakeCXXCompilerABI.cpp
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang++
+export XL_XLCMP_PATH=/opt/IBM/xlc/16.1.0:/opt/IBM/xlC/16.1.0
+export XL_COMPILER=xlc++
+export XL_ASMOBJFILES=/tmp/xlcAS3IXqid
+export "XL_DIS=/opt/IBM/xlc/16.1.0/exe/dis -o "CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o" "CMakeCXXCompilerABI.o""
+/opt/IBM/xlC/16.1.0/exe/xlC2entry -qosvar=aix.7.2 -qalias=ansi -qthreaded -D_THREAD_SAFE -Wno-parentheses -Wno-unused-value -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX50 -D_AIX51 -D_AIX52 -D_AIX53 -D_AIX61 -D_AIX71 -D_AIX72 -D_IBMR2 -D_POWER -xc++ -qasm_as=/bin/as -qcpp_stdinc=/opt/IBM/xlC/16.1.0/include2/c++:/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -qc_stdinc=/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -oCMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o /tmp/CMake/Modules/CMakeCXXCompilerABI.cpp /tmp/xlcW03uXqia /tmp/xlcW137Xqib /dev/null /tmp/xlcL3QXqieF.lst /dev/null /tmp/xlcW23AXqic
+export XL_BACKEND=/opt/IBM/xlc/16.1.0/exe/xlCcode
+export XL_LINKER=/bin/ld
+/opt/IBM/xlc/16.1.0/exe/xlCcode -qalias=ansi -qthreaded /tmp/xlcW03uXqia /tmp/xlcW137Xqib CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o /tmp/xlcL3QXqieB.lst /tmp/xlcW23AXqic
+rm /tmp/xlcAS3IXqid
+rm /tmp/xlcL3QXqie
+rm /tmp/xlcW03uXqia
+rm /tmp/xlcW137Xqib
+rm /tmp/xlcW23AXqic
+Linking CXX executable cmTC_b8490
+/tmp/CMake/bin/cmake -E cmake_link_script CMakeFiles/cmTC_b8490.dir/link.txt --verbose=1
+/opt/IBM/xlC/16.1.0/bin/xlclang++ -Wl,-bnoipath -Wl,-brtl -V -Wl,-bexpall CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b8490 -Wl,-blibpath:/usr/lib:/lib
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang++
+/bin/ld -b32 /lib/crt0.o /lib/crti.o -bpT:0x10000000 -bpD:0x20000000 -bnoipath -brtl -bexpall CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b8490 -blibpath:/usr/lib:/lib -bcdtors:all:0:s -btmplrename -L/opt/IBM/xlmass/9.1.0/lib/aix61 -L/opt/IBM/xlc/16.1.0/lib -lxlopt -lxlipa -lxl -L/opt/IBM/xlC/16.1.0/lib -lc++ -lCcore -lpthreads -lm -lc |
+/opt/IBM/xlC/16.1.0/bin/c++filt -S |
+/bin/sed '/317.*::virtual-fn-table-ptr$/ s/^\(.*: \)*{*\([^}]*\)\(}*.*\)::virtual-fn-table-ptr$/\1Virtual table for class "\2": Some possible causes are: first non-inline virtual function in "\2" is not defined or the class is a template instantiation and an explicit instantiation definition of the class is missing./'
+rm /tmp/xlcW05fS7ia
+rm /tmp/xlcW15rS7ib
+rm /tmp/xlcW25vS7ic
+gmake[1]: Leaving directory '/tmp/ii/CMakeFiles/CMakeTmp'
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output
new file mode 100644
index 000000000..7666f7e81
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output
@@ -0,0 +1 @@
+/opt/IBM/xlC/16.1.0/include2/c\+\+;/opt/IBM/xlC/16.1.0/include2;/opt/IBM/xlC/16.1.0/include2/aix;/opt/IBM/xlmass/9.1.0/include;/usr/include
diff --git a/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt b/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt
index 16bcb3689..66ff016f9 100644
--- a/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt
+++ b/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt
@@ -2,4 +2,4 @@
add_library(foo STATIC foo.cpp)
string(TOLOWER ${CMAKE_CXX_COMPILER_ID} compiler_id)
-target_compile_definitions(foo PRIVATE Foo=$<CXX_COMPILER_ID:${compiler_id}>)
+target_compile_definitions(foo PRIVATE Foo=$<CXX_COMPILER_ID:invalid,${compiler_id}>)
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index 644da600a..ad3f8f6d9 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -82,12 +82,9 @@ function(run_cmake test)
set(maybe_input_file "")
endif()
if(RunCMake_TEST_COMMAND)
- if(NOT RunCMake_TEST_COMMAND_WORKING_DIRECTORY)
- set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
- endif()
execute_process(
COMMAND ${RunCMake_TEST_COMMAND}
- WORKING_DIRECTORY "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}"
+ WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
OUTPUT_VARIABLE actual_stdout
ERROR_VARIABLE ${actual_stderr_var}
RESULT_VARIABLE actual_result
@@ -101,8 +98,14 @@ function(run_cmake test)
else()
set(_D_CMAKE_GENERATOR_INSTANCE "")
endif()
+ if(NOT RunCMake_TEST_NO_SOURCE_DIR)
+ set(maybe_source_dir "${RunCMake_TEST_SOURCE_DIR}")
+ else()
+ set(maybe_source_dir "")
+ endif()
execute_process(
- COMMAND ${CMAKE_COMMAND} "${RunCMake_TEST_SOURCE_DIR}"
+ COMMAND ${CMAKE_COMMAND}
+ ${maybe_source_dir}
-G "${RunCMake_GENERATOR}"
-A "${RunCMake_GENERATOR_PLATFORM}"
-T "${RunCMake_GENERATOR_TOOLSET}"
@@ -185,5 +188,10 @@ function(run_cmake_command test)
run_cmake(${test})
endfunction()
+function(run_cmake_with_options test)
+ set(RunCMake_TEST_OPTIONS "${ARGN}")
+ run_cmake(${test})
+endfunction()
+
# Protect RunCMake tests from calling environment.
unset(ENV{MAKEFLAGS})
diff --git a/Tests/RunCMake/Swift/E.swift b/Tests/RunCMake/Swift/E.swift
new file mode 100644
index 000000000..a41546787
--- /dev/null
+++ b/Tests/RunCMake/Swift/E.swift
@@ -0,0 +1,2 @@
+func f() {
+}
diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake
index 4864295dc..481704554 100644
--- a/Tests/RunCMake/Swift/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake
@@ -4,6 +4,10 @@ if(RunCMake_GENERATOR STREQUAL Xcode)
if(XCODE_BELOW_6_1)
run_cmake(XcodeTooOld)
endif()
+elseif(RunCMake_GENERATOR STREQUAL Ninja)
+ if(CMAKE_Swift_COMPILER)
+ run_cmake(Win32ExecutableDisallowed)
+ endif()
else()
run_cmake(NotSupported)
endif()
diff --git a/Tests/RunCMake/Swift/Win32ExecutableDisallowed-result.txt b/Tests/RunCMake/Swift/Win32ExecutableDisallowed-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/Swift/Win32ExecutableDisallowed-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Swift/Win32ExecutableDisallowed-stderr.txt b/Tests/RunCMake/Swift/Win32ExecutableDisallowed-stderr.txt
new file mode 100644
index 000000000..d78101a91
--- /dev/null
+++ b/Tests/RunCMake/Swift/Win32ExecutableDisallowed-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at Win32ExecutableDisallowed.cmake:[0-9]+ \(add_executable\):
+ WIN32_EXECUTABLE property is not supported on Swift executables
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Swift/Win32ExecutableDisallowed.cmake b/Tests/RunCMake/Swift/Win32ExecutableDisallowed.cmake
new file mode 100644
index 000000000..02d544749
--- /dev/null
+++ b/Tests/RunCMake/Swift/Win32ExecutableDisallowed.cmake
@@ -0,0 +1,4 @@
+enable_language(Swift)
+add_executable(E E.swift)
+set_target_properties(E PROPERTIES
+ WIN32_EXECUTABLE TRUE)
diff --git a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt
index 3f5224487..f3ee8951b 100644
--- a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt
+++ b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at UnterminatedCall1.cmake:2:
+CMake Error at UnterminatedCall1.cmake:1:
Parse error. Function missing ending "\)". End of file reached.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Syntax/UnterminatedCall1.cmake b/Tests/RunCMake/Syntax/UnterminatedCall1.cmake
index 1166109c9..e1d211877 100644
--- a/Tests/RunCMake/Syntax/UnterminatedCall1.cmake
+++ b/Tests/RunCMake/Syntax/UnterminatedCall1.cmake
@@ -1 +1,4 @@
message(
+
+
+message("Additional message")
diff --git a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt
index 18656f713..04216c32f 100644
--- a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt
+++ b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at UnterminatedCall2.cmake:4:
+CMake Error at UnterminatedCall2.cmake:3:
Parse error. Function missing ending "\)". End of file reached.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Syntax/UnterminatedCall2.cmake b/Tests/RunCMake/Syntax/UnterminatedCall2.cmake
index 26e9e6223..8d4088dcb 100644
--- a/Tests/RunCMake/Syntax/UnterminatedCall2.cmake
+++ b/Tests/RunCMake/Syntax/UnterminatedCall2.cmake
@@ -1,3 +1,6 @@
set(var "\
")
message(
+
+
+message("Additional message")
diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
index a66794ce8..77c4afd08 100644
--- a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
+++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
@@ -1,8 +1,9 @@
-CMake Error at NotObjlibTarget.cmake:3 \(file\):
+CMake Error at NotObjlibTarget.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
- \$<TARGET_OBJECTS:StaticLib>
+ \$<TARGET_OBJECTS:IFaceLib>
- Objects of target "StaticLib" referenced but is not an OBJECT library.
+ Objects of target "IFaceLib" referenced but is not an allowed library types
+ \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake
index 3bb3e374d..9fec369a7 100644
--- a/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake
+++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake
@@ -1,3 +1,3 @@
-add_library(StaticLib empty.cpp)
+add_library(IFaceLib INTERFACE )
-file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_output CONTENT $<TARGET_OBJECTS:StaticLib>)
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_output CONTENT $<TARGET_OBJECTS:IFaceLib>)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt
index fec12ae83..6da79b7d5 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt
@@ -47,4 +47,6 @@
\$<TARGET_PROPERTY:>
\$<TARGET_PROPERTY:...> expression requires a non-empty property name.
-*)+$
+*)+
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt
index 75865adc1..d40b16baa 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt
@@ -5,4 +5,6 @@ CMake Error at BadNonTarget.cmake:7 \(include_directories\):
Target "NonExistent" not found.
Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt
index f0f71ecf4..fa2686193 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt
@@ -34,4 +34,6 @@
\$<TARGET_PROPERTY:BadSelfReference6,COMPILE_DEFINITIONS>
Self reference on target "BadSelfReference6".
-*)+$
+*)+
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/UseSWIG/CMP0086-common.cmake b/Tests/RunCMake/UseSWIG/CMP0086-common.cmake
index c02592a94..ef9021813 100644
--- a/Tests/RunCMake/UseSWIG/CMP0086-common.cmake
+++ b/Tests/RunCMake/UseSWIG/CMP0086-common.cmake
@@ -8,4 +8,4 @@ include(UseSWIG)
set_property (SOURCE example.i PROPERTY SWIG_MODULE_NAME "new_example")
swig_add_library(example LANGUAGE python TYPE MODULE SOURCES example.i)
-target_link_libraries(example PRIVATE Python::Python)
+target_link_libraries(example PRIVATE Python::Module)
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index df253a913..55ca9ea39 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -1,7 +1,9 @@
include(RunCMake)
+cmake_policy(SET CMP0054 NEW)
run_cmake(VsCSharpCompilerOpts)
run_cmake(ExplicitCMakeLists)
+run_cmake(RuntimeLibrary)
run_cmake(SourceGroupCMakeLists)
run_cmake(VsConfigurationType)
@@ -18,3 +20,9 @@ run_cmake(VsCSharpDeployFiles)
run_cmake(VSCSharpDefines)
run_cmake(VsSdkDirectories)
run_cmake(VsGlobals)
+run_cmake(VsProjectImport)
+run_cmake(VsPackageReferences)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+ run_cmake(VsJustMyCode)
+endif()
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
new file mode 100644
index 000000000..689b35f4c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
@@ -0,0 +1,36 @@
+macro(RuntimeLibrary_check tgt rtl_expect)
+ set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj")
+ if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.")
+ return()
+ endif()
+
+ set(HAVE_Runtimelibrary 0)
+
+ file(STRINGS "${vcProjectFile}" lines)
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<RuntimeLibrary>([^<>]+)</RuntimeLibrary>")
+ set(rtl_actual "${CMAKE_MATCH_1}")
+ if(NOT "${rtl_actual}" STREQUAL "${rtl_expect}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has RuntimeLibrary '${rtl_actual}', not '${rtl_expect}'.")
+ return()
+ endif()
+ set(HAVE_Runtimelibrary 1)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT HAVE_Runtimelibrary AND NOT "${rtl_expect}" STREQUAL "")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a RuntimeLibrary field.")
+ return()
+ endif()
+endmacro()
+
+RuntimeLibrary_check(default-C MultiThreadedDebugDLL)
+RuntimeLibrary_check(default-CXX MultiThreadedDebugDLL)
+RuntimeLibrary_check(empty-C "")
+RuntimeLibrary_check(empty-CXX "")
+RuntimeLibrary_check(MTd-C MultiThreadedDebug)
+RuntimeLibrary_check(MTd-CXX MultiThreadedDebug)
+RuntimeLibrary_check(MT-C MultiThreaded)
+RuntimeLibrary_check(MT-CXX MultiThreaded)
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
new file mode 100644
index 000000000..d7787c8f8
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
@@ -0,0 +1,20 @@
+set(CMAKE_CONFIGURATION_TYPES Debug)
+cmake_policy(SET CMP0091 NEW)
+enable_language(C)
+enable_language(CXX)
+
+add_library(default-C empty.c)
+add_library(default-CXX empty.cxx)
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY "")
+add_library(empty-C empty.c)
+add_library(empty-CXX empty.cxx)
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug")
+add_library(MTd-C empty.c)
+add_library(MTd-CXX empty.cxx)
+
+add_library(MT-C empty.c)
+set_property(TARGET MT-C PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
+add_library(MT-CXX empty.cxx)
+set_property(TARGET MT-CXX PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
diff --git a/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
new file mode 100644
index 000000000..7119976f0
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
@@ -0,0 +1,38 @@
+macro(VsJustMyCode_check tgt jmc_expect)
+ set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj")
+ if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.")
+ return()
+ endif()
+
+ set(HAVE_JMC 0)
+
+ file(STRINGS "${vcProjectFile}" lines)
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<SupportJustMyCode>([^<>]+)</SupportJustMyCode>")
+ set(jmc_actual "${CMAKE_MATCH_1}")
+ if(NOT "${jmc_actual}" STREQUAL "${jmc_expect}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has <SupportJustMyCode> '${jmc_actual}', not '${jmc_expect}'.")
+ return()
+ endif()
+ set(HAVE_JMC 1)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT HAVE_JMC AND NOT "${jmc_expect}" STREQUAL "")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <SupportJustMyCode> property group.")
+ return()
+ endif()
+endmacro()
+
+VsJustMyCode_check(JMC-default-C "")
+VsJustMyCode_check(JMC-default-CXX "")
+VsJustMyCode_check(JMC-ON-C true)
+VsJustMyCode_check(JMC-ON-CXX true)
+VsJustMyCode_check(JMC-OFF-C "")
+VsJustMyCode_check(JMC-OFF-CXX "")
+VsJustMyCode_check(JMC-TGT-ON-C true)
+VsJustMyCode_check(JMC-TGT-ON-CXX true)
+VsJustMyCode_check(JMC-TGT-OFF-C "")
+VsJustMyCode_check(JMC-TGT-OFF-CXX "")
diff --git a/Tests/RunCMake/VS10Project/VsJustMyCode.cmake b/Tests/RunCMake/VS10Project/VsJustMyCode.cmake
new file mode 100644
index 000000000..b39f30f6c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsJustMyCode.cmake
@@ -0,0 +1,24 @@
+set(CMAKE_CONFIGURATION_TYPES Debug)
+enable_language(C)
+enable_language(CXX)
+
+add_library(JMC-default-C empty.c)
+add_library(JMC-default-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-OFF-C empty.c)
+add_library(JMC-OFF-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-ON-C empty.c)
+add_library(JMC-ON-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-TGT-ON-C empty.c)
+set_property(TARGET JMC-TGT-ON-C PROPERTY VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-TGT-ON-CXX empty.cxx)
+set_property(TARGET JMC-TGT-ON-CXX PROPERTY VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-TGT-OFF-C empty.c)
+set_property(TARGET JMC-TGT-OFF-C PROPERTY VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-TGT-OFF-CXX empty.cxx)
+set_property(TARGET JMC-TGT-OFF-CXX PROPERTY VS_JUST_MY_CODE_DEBUGGING OFF)
diff --git a/Tests/RunCMake/VS10Project/VsPackageReferences-check.cmake b/Tests/RunCMake/VS10Project/VsPackageReferences-check.cmake
new file mode 100644
index 000000000..4ff5327a9
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsPackageReferences-check.cmake
@@ -0,0 +1,39 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file foo.vcxproj does not exist.")
+ return()
+endif()
+
+
+set(test1Library "boost")
+set(test1Version "1.7.0")
+
+
+set(test2Library "SFML")
+set(test2Version "2.2.0")
+
+set(Library1Found FALSE)
+set(Library2Found FALSE)
+
+file(STRINGS "${vcProjectFile}" lines)
+
+foreach(i 1 2)
+ set(testLibrary "${test${i}Library}")
+ set(testVersion "${test${i}Version}")
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<PackageReference Include=\"${testLibrary}\".*>$")
+ if(line MATCHES "^ *<PackageReference .* Version=\"${testVersion}\".*>$")
+ set(Library${i}Found TRUE)
+ message(STATUS "foo.vcxproj is using package reference ${testLibrary} with version ${testVersion}")
+ elseif()
+ message(STATUS "foo.vcxproj failed to define reference ${testLibrary} with version ${testVersion}")
+ set(Library${i}Found FALSE)
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT Library1Found OR NOT Library2Found)
+ set(RunCMake_TEST_FAILED "Failed to find package references")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsPackageReferences.cmake b/Tests/RunCMake/VS10Project/VsPackageReferences.cmake
new file mode 100644
index 000000000..224ab18d7
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsPackageReferences.cmake
@@ -0,0 +1,4 @@
+enable_language(CXX)
+add_library(foo foo.cpp)
+
+set_property(TARGET foo PROPERTY VS_PACKAGE_REFERENCES "boost_1.7.0;SFML_2.2.0")
diff --git a/Tests/RunCMake/VS10Project/VsProjectImport-check.cmake b/Tests/RunCMake/VS10Project/VsProjectImport-check.cmake
new file mode 100644
index 000000000..e438bf46d
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsProjectImport-check.cmake
@@ -0,0 +1,28 @@
+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(test1Import "path\\\\to\\\\nuget_packages\\\\Foo.1.0.0\\\\build\\\\Foo.props")
+set(test2Import "path\\\\to\\\\nuget_packages\\\\Bar.1.0.0\\\\build\\\\Bar.props")
+
+set(import1Found FALSE)
+set(import2Found FALSE)
+
+file(STRINGS "${vcProjectFile}" lines)
+
+foreach(i 1 2)
+ set(testImport "${test${i}Import}")
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<Import Project=\".*${test1Import}\" />$")
+ message(STATUS "foo.vcxproj is using project import ${testImport}")
+ set(import${i}Found TRUE)
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT import1Found OR NOT import2Found)
+ set(RunCMake_TEST_FAILED "Imported project not found.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsProjectImport.cmake b/Tests/RunCMake/VS10Project/VsProjectImport.cmake
new file mode 100644
index 000000000..70bddedf8
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsProjectImport.cmake
@@ -0,0 +1,11 @@
+enable_language(CXX)
+add_library(foo foo.cpp)
+
+set(test1Import "path/to/nuget_packages/Foo.1.0.0/build/Foo.props")
+set(test2Import "path/to/nuget_packages/Bar.1.0.0/build/Bar.props")
+
+set_property(TARGET foo PROPERTY
+ VS_PROJECT_IMPORT
+ ${test1Import}
+ ${test2Import}
+ )
diff --git a/Tests/RunCMake/VS10Project/empty.c b/Tests/RunCMake/VS10Project/empty.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/empty.c
diff --git a/Tests/RunCMake/VS10Project/empty.cxx b/Tests/RunCMake/VS10Project/empty.cxx
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/empty.cxx
diff --git a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
index 6ab3833bf..dab1c33a3 100644
--- a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
+++ b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
@@ -40,3 +40,62 @@ if(NOT FoundToolsVersion4)
set(RunCMake_TEST_FAILED "Failed to find correct ToolsVersion=\"4.0\" .")
return()
endif()
+
+#
+# Test solution file deployment items.
+#
+
+set(vcSlnFile "${RunCMake_TEST_BINARY_DIR}/VsCEDebuggerDeploy.sln")
+if(NOT EXISTS "${vcSlnFile}")
+ set(RunCMake_TEST_FAILED "Solution file ${vcSlnFile} does not exist.")
+ return()
+endif()
+
+
+if( NOT ${CMAKE_SYSTEM_NAME} STREQUAL "WindowsCE" )
+ set(RunCMake_TEST_FAILED "Test only valid for WindowsCE")
+ return()
+endif()
+
+
+set(FooProjGUID "")
+set(FoundFooProj FALSE)
+set(InFooProj FALSE)
+set(FoundReleaseDeploy FALSE)
+set(DeployConfigs Debug MinSizeRel RelWithDebInfo )
+
+file(STRINGS "${vcSlnFile}" lines)
+foreach(line IN LISTS lines)
+#message(STATUS "${line}")
+ if( (NOT InFooProj ) AND (line MATCHES "^[ \\t]*Project\\(\"{[A-F0-9-]+}\"\\) = \"foo\", \"foo.vcxproj\", \"({[A-F0-9-]+})\"[ \\t]*$"))
+ # First, identify the GUID for the foo project, and record it.
+ set(FoundFooProj TRUE)
+ set(InFooProj TRUE)
+ set(FooProjGUID ${CMAKE_MATCH_1})
+ elseif(InFooProj AND line MATCHES "EndProject")
+ set(InFooProj FALSE)
+ elseif((NOT InFooProj) AND line MATCHES "${FooProjGUID}\\.Release.*\\.Deploy\\.0")
+ # If foo's Release configuration is set to deploy, this is the error.
+ set(FoundReleaseDeploy TRUE)
+ endif()
+ if( line MATCHES "{[A-F0-9-]+}\\.([^\\|]+).*\\.Deploy\\.0" )
+ # Check that the other configurations ARE set to deploy.
+ list( REMOVE_ITEM DeployConfigs ${CMAKE_MATCH_1})
+ endif()
+endforeach()
+
+if(FoundReleaseDeploy)
+ set(RunCMake_TEST_FAILED "Release deployment not inhibited by VS_NO_SOLUTION_DEPLOY_Release.")
+ return()
+endif()
+
+if(NOT FoundFooProj)
+ set(RunCMake_TEST_FAILED "Failed to find foo project in the solution.")
+ return()
+endif()
+
+list(LENGTH DeployConfigs length)
+if( length GREATER 0 )
+ set(RunCMake_TEST_FAILED "Failed to find Deploy lines for non-Release configurations. (${length})")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
index 948f14c7b..611db0adb 100644
--- a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
+++ b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
@@ -4,10 +4,11 @@ set(DEPLOY_DIR
"temp\\foodir"
)
-add_library(foo foo.cpp)
+add_library(foo SHARED foo.cpp)
set_target_properties(foo
PROPERTIES
DEPLOYMENT_ADDITIONAL_FILES "foo.dll|\\foo\\src\\dir\\on\\host|$(RemoteDirectory)|0;bar.dll|\\bar\\src\\dir|$(RemoteDirectory)bardir|0"
DEPLOYMENT_REMOTE_DIRECTORY ${DEPLOY_DIR}
+ VS_NO_SOLUTION_DEPLOY $<CONFIG:Release>
)
diff --git a/Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt b/Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt
index ca8c33f36..a63591fff 100644
--- a/Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt
+++ b/Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt
@@ -1 +1 @@
-CMake Error: Target visibility_preset uses unsupported value \"hiden\" for CXX_VISIBILITY_PRESET
+CMake Error: Target visibility_preset uses unsupported value \"hiden\" for CXX_VISIBILITY_PRESET. The supported values are: default, hidden, protected, and internal.
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt
index 46a294d92..69c61e698 100644
--- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt
@@ -5,4 +5,6 @@
specified for source:
- .*/Tests/RunCMake/XcodeProject/main.c$
+ .*/Tests/RunCMake/XcodeProject/main.c
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt
index 650064920..c3e9e318a 100644
--- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt
@@ -5,4 +5,6 @@
specified for source:
- .*/Tests/RunCMake/XcodeProject/main.c$
+ .*/Tests/RunCMake/XcodeProject/main.c
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
index f9b8ee7f7..ff70b95a3 100644
--- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
@@ -5,4 +5,6 @@
specified for source:
- .*/Tests/RunCMake/XcodeProject/main.c$
+ .*/Tests/RunCMake/XcodeProject/main.c
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
index bfca02000..100008a44 100644
--- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
@@ -5,4 +5,6 @@
specified for source:
- .*/Tests/RunCMake/XcodeProject/main.c$
+ .*/Tests/RunCMake/XcodeProject/main.c
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
index f675d819a..88077b3b5 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
@@ -7,6 +7,13 @@ function(check_property property matcher)
endif()
endfunction()
+function(expect_no_schema target)
+ set(schema "${RunCMake_TEST_BINARY_DIR}/XcodeSchemaProperty.xcodeproj/xcshareddata/xcschemes/${target}.xcscheme")
+ if(EXISTS ${schema})
+ message(SEND_ERROR "Found unexpected schema ${schema}")
+ endif()
+endfunction()
+
check_property("ADDRESS_SANITIZER" "enableAddressSanitizer")
check_property("ADDRESS_SANITIZER_USE_AFTER_RETURN" "enableASanStackUseAfterReturn")
check_property("THREAD_SANITIZER" "enableThreadSanitizer")
@@ -31,3 +38,5 @@ check_property("ENVIRONMENT" [=[key="FOO"]=])
check_property("ENVIRONMENT" [=[value="foo"]=])
check_property("ENVIRONMENT" [=[key="BAR"]=])
check_property("ENVIRONMENT" [=[value="bar"]=])
+
+expect_no_schema("NoSchema")
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
index 2b72a64f1..73ef5caaf 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
@@ -35,3 +35,6 @@ endfunction()
create_scheme_for_property(EXECUTABLE myExecutable)
create_scheme_for_property(ARGUMENTS "--foo;--bar=baz")
create_scheme_for_property(ENVIRONMENT "FOO=foo;BAR=bar")
+
+add_executable(NoSchema main.cpp)
+set_target_properties(NoSchema PROPERTIES XCODE_GENERATE_SCHEME OFF)
diff --git a/Tests/RunCMake/add_executable/NoSources-stderr.txt b/Tests/RunCMake/add_executable/NoSources-stderr.txt
index 4fcfd4991..abefc6d12 100644
--- a/Tests/RunCMake/add_executable/NoSources-stderr.txt
+++ b/Tests/RunCMake/add_executable/NoSources-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at NoSources.cmake:[0-9]+ \(add_executable\):
No SOURCES given to target: TestExeWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt
index 5561daa39..80026bfca 100644
--- a/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt
+++ b/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at NoSourcesButLinkObjects.cmake:[0-9]+ \(add_executable\):
No SOURCES given to target: TestExeWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt b/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt
index 41da38101..72b92ced8 100644
--- a/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt
+++ b/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at MODULEwithNoSources.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestModuleLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt
index 67dd87c3f..1490524e0 100644
--- a/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt
+++ b/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at MODULEwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestModuleLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt
index 20d3a8a84..be7634c87 100644
--- a/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt
+++ b/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at OBJECTwithNoSources.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestObjectLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt
index 1bcc114a1..3f8591666 100644
--- a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt
+++ b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestObjectLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt b/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt
index 5cedd62d0..471eda12a 100644
--- a/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt
+++ b/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at SHAREDwithNoSources.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestSharedLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt
index d621e7677..4bec7ae89 100644
--- a/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt
+++ b/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at SHAREDwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestSharedLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt b/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt
index 10b211280..f65522116 100644
--- a/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt
+++ b/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at STATICwithNoSources.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestStaticLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt
index 33c23b2f3..185aad801 100644
--- a/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt
+++ b/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt
@@ -1,4 +1,6 @@
^CMake Error at STATICwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
No SOURCES given to target: TestStaticLibWithoutSources
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
index ff676a6ba..f68600511 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
@@ -4,11 +4,3 @@ add_subdirectory(ExcludeFromAll EXCLUDE_FROM_ALL)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE foo)
-
-file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
-set(main_exe \"$<TARGET_FILE:main>\")
-set(foo_lib \"$<TARGET_FILE:foo>\")
-set(bar_lib \"$<TARGET_FILE:bar>\")
-set(zot_lib \"$<TARGET_FILE:zot>\")
-set(subinc_lib \"$<TARGET_FILE:subinc>\")
-")
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
index 790da542f..9e6462bf4 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
@@ -1,11 +1,20 @@
-project(ExcludeFromAllSub NONE)
+add_library(bar STATIC bar.cpp)
-add_library(bar STATIC EXCLUDE_FROM_ALL bar.cpp)
+add_library(foo STATIC foo.cpp)
-add_library(zot STATIC zot.cpp)
+add_library(baz STATIC foo.cpp)
+set_target_properties(baz PROPERTIES EXCLUDE_FROM_ALL OFF)
-add_library(foo STATIC foo.cpp)
-target_include_directories(foo PUBLIC .)
+file(GENERATE
+ OUTPUT "${CMAKE_BINARY_DIR}/main.txt"
+ CONTENT "$<TARGET_FILE_NAME:main>")
-add_library(subinc STATIC subinc.cpp)
-set_target_properties(subinc PROPERTIES EXCLUDE_FROM_ALL OFF)
+file(GENERATE
+ OUTPUT "${CMAKE_BINARY_DIR}/bar.txt"
+ CONTENT "$<TARGET_FILE_NAME:bar>")
+
+file(GENERATE
+ OUTPUT "${CMAKE_BINARY_DIR}/baz.txt"
+ CONTENT "$<TARGET_FILE_NAME:baz>")
+
+target_include_directories(foo PUBLIC .)
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
deleted file mode 100644
index 297ad1e22..000000000
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
- include(${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
- if(RunCMake_TEST_FAILED)
- return()
- endif()
-
- foreach(file
- "${foo_lib}"
- "${subinc_lib}"
- "${zot_lib}"
- )
- if(NOT EXISTS "${file}")
- set(RunCMake_TEST_FAILED
- "Artifact should exist but is missing:\n ${file}")
- return()
- endif()
- endforeach()
- foreach(file
- "${main_exe}"
- "${bar_lib}"
- )
- if(EXISTS "${file}")
- set(RunCMake_TEST_FAILED
- "Artifact should be missing but exists:\n ${file}")
- return()
- endif()
- endforeach()
-else()
- set(RunCMake_TEST_FAILED "
- '${RunCMake_TEST_BINARY_DIR}/check-debug.cmake' missing
-")
-endif()
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
index 433c03208..14ec4827f 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
@@ -1,35 +1,44 @@
-if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
- include(${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
- if(RunCMake_TEST_FAILED)
- return()
+# Use globbing to check if exes / libs were built because determining
+# exactly where these files will live inside a CMake -P script is
+# pretty challenging.
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/main.txt" main_exe)
+file(READ "${RunCMake_TEST_BINARY_DIR}/bar.txt" bar_lib)
+file(READ "${RunCMake_TEST_BINARY_DIR}/baz.txt" baz_lib)
+
+set(found_main FALSE)
+file(GLOB_RECURSE files
+ LIST_DIRECTORIES FALSE
+ RELATIVE "${RunCMake_TEST_BINARY_DIR}"
+ "${RunCMake_TEST_BINARY_DIR}/*")
+foreach (file IN LISTS files)
+ if (file MATCHES "${main_exe}")
+ set(found_main TRUE)
endif()
+endforeach()
+if (NOT found_main)
+ set(RunCMake_TEST_FAILED "'main' missing from ${RunCMake_TEST_BINARY_DIR}")
+endif()
- foreach(file
- "${foo_lib}"
- "${subinc_lib}"
- "${main_exe}"
- )
- if(EXISTS "${file}")
- # Remove for next step of test.
- file(REMOVE "${file}")
- else()
- set(RunCMake_TEST_FAILED
- "Artifact should exist but is missing:\n ${file}")
- return()
- endif()
- endforeach()
- foreach(file
- "${zot_lib}"
- "${bar_lib}"
- )
- if(EXISTS "${file}")
- set(RunCMake_TEST_FAILED
- "Artifact should be missing but exists:\n ${file}")
- return()
- endif()
- endforeach()
-else()
- set(RunCMake_TEST_FAILED "
- '${RunCMake_TEST_BINARY_DIR}/check-debug.cmake' missing
-")
+set(found_bar FALSE)
+set(found_baz FALSE)
+file(GLOB_RECURSE files
+ LIST_DIRECTORIES FALSE
+ RELATIVE "${RunCMake_TEST_BINARY_DIR}/ExcludeFromAll"
+ "${RunCMake_TEST_BINARY_DIR}/ExcludeFromAll/*")
+foreach (file IN LISTS files)
+ if (file MATCHES "${bar_lib}")
+ set(found_bar TRUE)
+ endif()
+ if (file MATCHES "${baz_lib}")
+ set(found_baz TRUE)
+ endif()
+endforeach()
+if (found_bar)
+ set(RunCMake_TEST_FAILED
+ "'bar' was not excluded from ${RunCMake_TEST_BINARY_DIR}/ExcludeFromAll")
+endif()
+if (NOT found_baz)
+ set(RunCMake_TEST_FAILED
+ "'baz' missing from ${RunCMake_TEST_BINARY_DIR}/ExcludeFromAll")
endif()
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/subinc.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/subinc.cpp
deleted file mode 100644
index e9faacdba..000000000
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/subinc.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-int subinc()
-{
- return 0;
-}
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/zot.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/zot.cpp
deleted file mode 100644
index ba7e9661c..000000000
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/zot.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-int zot()
-{
- return 0;
-}
diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
index 951e03c8f..781e48371 100644
--- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
@@ -27,34 +27,14 @@ run_cmake_install(CMP0082-OLD -DCMP0082_VALUE=OLD)
run_cmake_install(CMP0082-NEW -DCMP0082_VALUE=NEW)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll-build)
-if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
- set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
-endif()
-run_cmake(ExcludeFromAll)
set(RunCMake_TEST_NO_CLEAN 1)
+
+file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+run_cmake(ExcludeFromAll)
set(RunCMake-check-file ExcludeFromAll/check.cmake)
-run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build . --config Debug)
-if(RunCMake_GENERATOR STREQUAL "Ninja")
- if(WIN32)
- set(slash [[\]])
- else()
- set(slash [[/]])
- endif()
- set(RunCMake-check-file ExcludeFromAll/check-sub.cmake)
- run_cmake_command(ExcludeFromAll-build-sub ${CMAKE_COMMAND} --build . --target "ExcludeFromAll${slash}all")
-elseif(RunCMake_GENERATOR MATCHES "Make")
- set(RunCMake-check-file ExcludeFromAll/check-sub.cmake)
- set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY ${RunCMake_BINARY_DIR}/ExcludeFromAll-build/ExcludeFromAll)
- run_cmake_command(ExcludeFromAll-build-sub "${RunCMake_MAKE_PROGRAM}")
-elseif(RunCMake_GENERATOR MATCHES "^Visual Studio [1-9][0-9]")
- set(RunCMake-check-file ExcludeFromAll/check-sub.cmake)
- run_cmake_command(ExcludeFromAll-build-sub ${CMAKE_COMMAND} --build ExcludeFromAll --config Debug)
-elseif(RunCMake_GENERATOR STREQUAL "Xcode")
- set(RunCMake-check-file ExcludeFromAll/check-sub.cmake)
- set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY ${RunCMake_BINARY_DIR}/ExcludeFromAll-build/ExcludeFromAll)
- run_cmake_command(ExcludeFromAll-build-sub xcodebuild -configuration Debug)
-endif()
-unset(RunCMake-check-file)
-unset(RunCMake_TEST_NO_CLEAN)
-unset(RunCMake_TEST_OPTIONS)
+run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build .)
+
unset(RunCMake_TEST_BINARY_DIR)
+unset(RunCMake_TEST_NO_CLEAN)
diff --git a/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake b/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake
new file mode 100644
index 000000000..561f9c03b
--- /dev/null
+++ b/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake
@@ -0,0 +1,133 @@
+include(${CMAKE_CURRENT_LIST_DIR}/test_utils.cmake)
+
+# No keywords that miss any values, _KEYWORDS_MISSING_VALUES should not be defined
+cmake_parse_arguments(PREF "" "P1" "P2" P1 p1 P2 p2_a p2_b)
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+
+# Keyword should even be deleted from the actual scope
+set(PREF_KEYWORDS_MISSING_VALUES "What ever")
+cmake_parse_arguments(PREF "" "" "")
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+
+# Given missing keywords as only option
+cmake_parse_arguments(PREF "" "P1" "P2" P1)
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "P1")
+TEST(PREF_P1 "UNDEFINED")
+TEST(PREF_UNPARSED_ARGUMENTS "UNDEFINED")
+
+# Mixed with unparsed arguments
+cmake_parse_arguments(UPREF "" "P1" "P2" A B P2 C P1)
+TEST(UPREF_KEYWORDS_MISSING_VALUES "P1")
+TEST(UPREF_UNPARSED_ARGUMENTS A B)
+
+# one_value_keyword followed by option
+cmake_parse_arguments(REF "OP" "P1" "" P1 OP)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_OP "TRUE")
+
+# Counter Test
+cmake_parse_arguments(REF "OP" "P1" "" P1 p1 OP)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_OP "TRUE")
+
+# one_value_keyword followed by a one_value_keyword
+cmake_parse_arguments(REF "" "P1;P2" "" P1 P2 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# Counter Test
+cmake_parse_arguments(REF "" "P1;P2" "" P1 p1 P2 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# one_value_keyword followed by a multi_value_keywords
+cmake_parse_arguments(REF "" "P1" "P2" P1 P2 p1 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 p1 p2)
+
+# Counter Examples
+cmake_parse_arguments(REF "" "P1" "P2" P1 p1 P2 p1 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 p1 p2)
+
+# multi_value_keywords as only option
+cmake_parse_arguments(REF "" "P1" "P2" P2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# multi_value_keywords followed by option
+cmake_parse_arguments(REF "O1" "" "P1" P1 O1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_O1 "TRUE")
+
+# counter test
+cmake_parse_arguments(REF "O1" "" "P1" P1 p1 p2 O1)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1;p2")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_O1 "TRUE")
+
+# multi_value_keywords followed by one_value_keyword
+cmake_parse_arguments(REF "" "P1" "P2" P2 P1 p1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# counter test
+cmake_parse_arguments(REF "" "P1" "P2" P2 p2 P1 p1)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# one_value_keyword as last argument
+cmake_parse_arguments(REF "" "P1" "P2" A P2 p2 P1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "A")
+TEST(REF_P2 "p2")
+
+# multi_value_keywords as last argument
+cmake_parse_arguments(REF "" "P1" "P2" P1 p1 P2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "p1")
+TEST(REF_P2 "UNDEFINED")
+
+# Multiple one_value_keyword and multi_value_keywords at different places
+cmake_parse_arguments(REF "O1;O2" "P1" "P2" P1 O1 P2 O2)
+TEST(REF_KEYWORDS_MISSING_VALUES P1 P2)
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# Duplicated missing keywords
+cmake_parse_arguments(REF "O1;O2" "P1" "P2" P1 O1 P2 O2 P1 P2)
+TEST(REF_KEYWORDS_MISSING_VALUES P1 P2)
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# make sure keywords that are never used, don't get added to KEYWORDS_MISSING_VALUES
+cmake_parse_arguments(REF "O1;O2" "P1" "P2")
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_O1 FALSE)
+TEST(REF_O2 FALSE)
+TEST(REF_P1 UNDEFINED)
+TEST(REF_P2 UNDEFINED)
diff --git a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
index 1e15b3b2c..505840d7a 100644
--- a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
+++ b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
@@ -11,3 +11,4 @@ run_cmake(BadArgvN2)
run_cmake(BadArgvN3)
run_cmake(BadArgvN4)
run_cmake(CornerCasesArgvN)
+run_cmake(KeyWordsMissingValues)
diff --git a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
index 4d7d29bad..78856b410 100644
--- a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
@@ -31,7 +31,7 @@ run_ctest_submit(CDashUploadNone CDASH_UPLOAD)
run_ctest_submit(CDashUploadMissingFile CDASH_UPLOAD bad-upload)
run_ctest_submit(CDashUploadRetry CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo RETRY_COUNT 2 RETRY_DELAY 1 INTERNAL_TEST_CHECKSUM)
run_ctest_submit(CDashSubmitQuiet QUIET)
-run_ctest_submit_debug(CDashSubmitVerbose)
+run_ctest_submit_debug(CDashSubmitVerbose BUILD_ID my_build_id)
run_ctest_submit_debug(FILESNoBuildId FILES ${CMAKE_CURRENT_LIST_FILE})
run_ctest_submit_debug(CDashSubmitHeaders HTTPHEADER "Authorization: Bearer asdf")
run_ctest_submit_debug(CDashUploadHeaders CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo HTTPHEADER "Authorization: Bearer asdf")
diff --git a/Tests/RunCMake/ctest_update/CMakeLists.txt.in b/Tests/RunCMake/ctest_update/CMakeLists.txt.in
new file mode 100644
index 000000000..ecf0e54ea
--- /dev/null
+++ b/Tests/RunCMake/ctest_update/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(CTestTest@CASE_NAME@ NONE)
+include(CTest)
+@CASE_CMAKELISTS_SUFFIX_CODE@
diff --git a/Tests/RunCMake/ctest_update/RunCMakeTest.cmake b/Tests/RunCMake/ctest_update/RunCMakeTest.cmake
new file mode 100644
index 000000000..f8d7665ab
--- /dev/null
+++ b/Tests/RunCMake/ctest_update/RunCMakeTest.cmake
@@ -0,0 +1,25 @@
+include(RunCTest)
+set(CASE_CTEST_UPDATE_ARGS "")
+function(run_ctest_update CASE_NAME)
+ set(CASE_CTEST_UPDATE_ARGS "${ARGN}")
+ run_ctest(${CASE_NAME})
+endfunction()
+
+run_ctest_update(UpdateQuiet QUIET)
+
+function(run_UpdateChangeId)
+ set(CASE_TEST_PREFIX_CODE [[
+ set(CTEST_CHANGE_ID "<>1")
+ ]])
+
+ run_ctest(UpdateChangeId)
+endfunction()
+run_UpdateChangeId()
+
+function(run_UpdateVersionOverride)
+ set(CASE_TEST_PREFIX_CODE [[
+ set(CTEST_UPDATE_VERSION_OVERRIDE "qwertyuiop")
+ ]])
+ run_ctest(UpdateVersionOverride)
+endfunction()
+run_UpdateVersionOverride()
diff --git a/Tests/RunCMake/ctest_update/UpdateActualVersion-check.cmake b/Tests/RunCMake/ctest_update/UpdateActualVersion-check.cmake
new file mode 100644
index 000000000..12bd5a00d
--- /dev/null
+++ b/Tests/RunCMake/ctest_update/UpdateActualVersion-check.cmake
@@ -0,0 +1,12 @@
+file(GLOB update_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Update.xml")
+if(update_xml_file)
+ file(READ "${update_xml_file}" update_xml LIMIT 4096)
+ if(NOT update_xml MATCHES "qwertyuiop")
+ string(REPLACE "\n" "\n " update_xml " ${update_xml}")
+ set(RunCMake_TEST_FAILED
+ "Did not find 'qwertyuiop' in Update.xml:\n${update_xml}"
+ )
+ endif()
+else()
+ set(RunCMake_TEST_FAILED "Update.xml not found")
+endif()
diff --git a/Tests/RunCMake/ctest_update/UpdateChangeId-check.cmake b/Tests/RunCMake/ctest_update/UpdateChangeId-check.cmake
new file mode 100644
index 000000000..382fbec6a
--- /dev/null
+++ b/Tests/RunCMake/ctest_update/UpdateChangeId-check.cmake
@@ -0,0 +1,12 @@
+file(GLOB update_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Update.xml")
+if(update_xml_file)
+ file(READ "${update_xml_file}" update_xml LIMIT 4096)
+ if(NOT update_xml MATCHES [[ChangeId>&lt;&gt;1]])
+ string(REPLACE "\n" "\n " update_xml " ${update_xml}")
+ set(RunCMake_TEST_FAILED
+ "Update.xml does not have expected ChangeId:\n${update_xml}"
+ )
+ endif()
+else()
+ set(RunCMake_TEST_FAILED "Update.xml not found")
+endif()
diff --git a/Tests/RunCMake/ctest_update/test.cmake.in b/Tests/RunCMake/ctest_update/test.cmake.in
new file mode 100644
index 000000000..25b842324
--- /dev/null
+++ b/Tests/RunCMake/ctest_update/test.cmake.in
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+@CASE_TEST_PREFIX_CODE@
+
+set(CTEST_SITE "test-site")
+set(CTEST_BUILD_NAME "test-build-name")
+set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+
+# FIXME: update test to do someting meaningful with this.
+set(CTEST_UPDATE_COMMAND "not-actually-used")
+
+set(ctest_test_args "@CASE_CTEST_UPDATE_ARGS@")
+ctest_start(Experimental)
+ctest_update(${ctest_update_args})
diff --git a/Tests/RunCMake/execute_process/EchoCommand-result.txt b/Tests/RunCMake/execute_process/EchoCommand-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/execute_process/EchoCommand-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand-stderr.txt
new file mode 100644
index 000000000..f10ece8c4
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand-stderr.txt
@@ -0,0 +1,5 @@
+.*cmake.*-E' 'echo' '-- 2 COMMAND_ECHO STDERR'
+.*cmake.*-E' 'echo' '-- 4 COMMAND_ECHO STDERR'
+.*cmake.*-E' 'echo' '-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR'
+CMake Error at .*EchoCommand.cmake:.* \(execute_process\):
+ CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to 'BAD' expected STDERR|STDOUT|NONE$
diff --git a/Tests/RunCMake/execute_process/EchoCommand-stdout.txt b/Tests/RunCMake/execute_process/EchoCommand-stdout.txt
new file mode 100644
index 000000000..0954b3b3d
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand-stdout.txt
@@ -0,0 +1,12 @@
+.*cmake.*-E' 'echo' '-- 1 COMMAND_ECHO STDOUT'
+-- 1 COMMAND_ECHO STDOUT
+-- 2 COMMAND_ECHO STDERR
+.*cmake.* '-E' 'echo' '-- 3 COMMAND_ECHO STDOUT'
+-- 3 COMMAND_ECHO STDOUT
+-- 4 COMMAND_ECHO STDERR
+.*cmake.* '-E' 'echo' '-- 5 COMMAND_ECHO STDOUT'
+-- 5 COMMAND_ECHO STDOUT
+-- 6 COMMAND_ECHO NONE
+.*cmake.* '-E' 'echo' '-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT'
+-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT
+-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR$
diff --git a/Tests/RunCMake/execute_process/EchoCommand.cmake b/Tests/RunCMake/execute_process/EchoCommand.cmake
new file mode 100644
index 000000000..9c7d13db6
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand.cmake
@@ -0,0 +1,41 @@
+if(CHECK_ERROR_OUTPUT_LOCATION)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 1 COMMAND_ECHO " COMMAND_ECHO )
+endif()
+# test COMMAND_ECHO STDOUT
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 1 COMMAND_ECHO STDOUT" COMMAND_ECHO STDOUT )
+# test COMMAND_ECHO STDERR
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 2 COMMAND_ECHO STDERR" COMMAND_ECHO STDERR )
+# test CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT
+set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT)
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 3 COMMAND_ECHO STDOUT" )
+# test CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDERR
+set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDERR)
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 4 COMMAND_ECHO STDERR" )
+# make sure local will override global settings
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 5 COMMAND_ECHO STDOUT" COMMAND_ECHO STDOUT )
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 6 COMMAND_ECHO NONE" COMMAND_ECHO NONE)
+# test both and make sure override works
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT" COMMAND_ECHO STDERR
+ COMMAND_ECHO STDOUT)
+execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR" COMMAND_ECHO STDOUT
+ COMMAND_ECHO STDERR)
+
+# check for bad arguments to global and local
+if(CHECK_GLOBAL)
+ # make sure a non STDERR or STDOUT value is an error
+ set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO BAD)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 9 - 1 CMAKE_EXECUTE_PROCESS_COMMAND_ECHO BAD" )
+else()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo
+ "-- 9 - 2 COMMAND_ECHO BAD" COMMAND_ECHO BAD)
+endif()
diff --git a/Tests/RunCMake/execute_process/EchoCommand2-result.txt b/Tests/RunCMake/execute_process/EchoCommand2-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt
new file mode 100644
index 000000000..4ae01c4fb
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt
@@ -0,0 +1,5 @@
+.*cmake.*-E' 'echo' '-- 2 COMMAND_ECHO STDERR'
+.*cmake.*-E' 'echo' '-- 4 COMMAND_ECHO STDERR'
+.*cmake.*-E' 'echo' '-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR'
+CMake Error at .*EchoCommand.cmake:.* \(execute_process\):
+ called with 'BAD' expected STDERR|STDOUT|NONE for COMMAND_ECHO.$
diff --git a/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt b/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt
new file mode 100644
index 000000000..0954b3b3d
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt
@@ -0,0 +1,12 @@
+.*cmake.*-E' 'echo' '-- 1 COMMAND_ECHO STDOUT'
+-- 1 COMMAND_ECHO STDOUT
+-- 2 COMMAND_ECHO STDERR
+.*cmake.* '-E' 'echo' '-- 3 COMMAND_ECHO STDOUT'
+-- 3 COMMAND_ECHO STDOUT
+-- 4 COMMAND_ECHO STDERR
+.*cmake.* '-E' 'echo' '-- 5 COMMAND_ECHO STDOUT'
+-- 5 COMMAND_ECHO STDOUT
+-- 6 COMMAND_ECHO NONE
+.*cmake.* '-E' 'echo' '-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT'
+-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT
+-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR$
diff --git a/Tests/RunCMake/execute_process/EchoCommand3-result.txt b/Tests/RunCMake/execute_process/EchoCommand3-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt
new file mode 100644
index 000000000..e27f1e6d2
--- /dev/null
+++ b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at .*EchoCommand.cmake:.*\(execute_process\):
+ execute_process called with no value for COMMAND_ECHO.
diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
index cb40b40a4..b203aabfd 100644
--- a/Tests/RunCMake/execute_process/RunCMakeTest.cmake
+++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
@@ -16,3 +16,11 @@ endif()
if(EXIT_CODE_EXE)
run_cmake_command(ExitValues ${CMAKE_COMMAND} -DEXIT_CODE_EXE=${EXIT_CODE_EXE} -P ${RunCMake_SOURCE_DIR}/ExitValues.cmake)
endif()
+
+run_cmake_command(EchoCommand ${CMAKE_COMMAND} -DCHECK_GLOBAL=TRUE
+ -P ${RunCMake_SOURCE_DIR}/EchoCommand.cmake)
+run_cmake_command(EchoCommand2 ${CMAKE_COMMAND} -P
+ ${RunCMake_SOURCE_DIR}/EchoCommand.cmake)
+run_cmake_command(EchoCommand3 ${CMAKE_COMMAND}
+ -DCHECK_ERROR_OUTPUT_LOCATION=TRUE -P
+ ${RunCMake_SOURCE_DIR}/EchoCommand.cmake)
diff --git a/Tests/RunCMake/export/AppendExport-stderr.txt b/Tests/RunCMake/export/AppendExport-stderr.txt
index d71620e5f..d12124c9a 100644
--- a/Tests/RunCMake/export/AppendExport-stderr.txt
+++ b/Tests/RunCMake/export/AppendExport-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at AppendExport.cmake:[0-9]+ \(export\):
- export EXPORT signature does not recognise the APPEND option.
+ export Unknown argument: "APPEND".
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/export/Empty.cmake b/Tests/RunCMake/export/Empty.cmake
new file mode 100644
index 000000000..2198ddf75
--- /dev/null
+++ b/Tests/RunCMake/export/Empty.cmake
@@ -0,0 +1 @@
+export(TARGETS FILE targets.cmake)
diff --git a/Tests/RunCMake/export/OldIface-stderr.txt b/Tests/RunCMake/export/OldIface-stderr.txt
index 818c2cb20..3cc10331e 100644
--- a/Tests/RunCMake/export/OldIface-stderr.txt
+++ b/Tests/RunCMake/export/OldIface-stderr.txt
@@ -1,5 +1,4 @@
CMake Error at OldIface.cmake:[0-9]+ \(export\):
- export EXPORT signature does not recognise the
- EXPORT_LINK_INTERFACE_LIBRARIES option.
+ export Unknown argument: "EXPORT_LINK_INTERFACE_LIBRARIES".
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake
index 46bb1fca3..97a0ca6d8 100644
--- a/Tests/RunCMake/export/RunCMakeTest.cmake
+++ b/Tests/RunCMake/export/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
include(RunCMake)
run_cmake(CustomTarget)
+run_cmake(Empty)
run_cmake(TargetNotFound)
run_cmake(AppendExport)
run_cmake(OldIface)
diff --git a/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN.cmake b/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN.cmake
new file mode 100644
index 000000000..d8a12ebba
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN.cmake
@@ -0,0 +1,168 @@
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/dest1")
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file1.txt")
+file(CREATE_LINK file1.txt "${CMAKE_BINARY_DIR}/file1.txt.sym" SYMBOLIC)
+file(TOUCH "${CMAKE_BINARY_DIR}/dest1/file1.txt.sym")
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file2.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file2")
+file(CREATE_LINK ../file2.txt "${CMAKE_BINARY_DIR}/file2/file2.txt.sym" SYMBOLIC)
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file3.txt")
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file3.txt" "${CMAKE_BINARY_DIR}/file3.txt.sym" SYMBOLIC)
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file4.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file4")
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file4.txt" "${CMAKE_BINARY_DIR}/file4/file4.txt.sym" SYMBOLIC)
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file5.txt")
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file6.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file6/file6")
+file(CREATE_LINK file6.txt "${CMAKE_BINARY_DIR}/file6.txt.sym.1" SYMBOLIC)
+file(CREATE_LINK ../file6.txt.sym.1 "${CMAKE_BINARY_DIR}/file6/file6.txt.sym.2" SYMBOLIC)
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file6/file6.txt.sym.2" "${CMAKE_BINARY_DIR}/file6/file6/file6.txt.sym.3" SYMBOLIC)
+file(CREATE_LINK file6.txt.sym.3 "${CMAKE_BINARY_DIR}/file6/file6/file6.txt.sym.4" SYMBOLIC)
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file7.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file7")
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file8.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file8")
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file8/../file8.txt" "${CMAKE_BINARY_DIR}/file8/file8.txt.sym" SYMBOLIC)
+
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file9")
+file(TOUCH "${CMAKE_BINARY_DIR}/file9/file9.txt")
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file9" "${CMAKE_BINARY_DIR}/file9.sym" SYMBOLIC)
+
+file(TOUCH "${CMAKE_BINARY_DIR}/file10.txt")
+file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/file10")
+file(CREATE_LINK "." "${CMAKE_BINARY_DIR}/file10/file10" SYMBOLIC)
+file(CREATE_LINK "${CMAKE_BINARY_DIR}/file10/file10/../file10.txt" "${CMAKE_BINARY_DIR}/file10/file10.txt.sym" SYMBOLIC)
+
+file(INSTALL
+ "${CMAKE_BINARY_DIR}/file1.txt.sym"
+ DESTINATION "${CMAKE_BINARY_DIR}/dest1"
+ FOLLOW_SYMLINK_CHAIN
+ )
+
+file(INSTALL
+ "${CMAKE_BINARY_DIR}/file1.txt.sym"
+ "${CMAKE_BINARY_DIR}/file2/file2.txt.sym"
+ "${CMAKE_BINARY_DIR}/file3.txt.sym"
+ "${CMAKE_BINARY_DIR}/file4/file4.txt.sym"
+ "${CMAKE_BINARY_DIR}/file5.txt"
+ "${CMAKE_BINARY_DIR}/file6/file6/file6.txt.sym.4"
+ "${CMAKE_BINARY_DIR}/file8/file8.txt.sym"
+ "${CMAKE_BINARY_DIR}/file7/../file7.txt"
+ "${CMAKE_BINARY_DIR}/file8.txt"
+ "${CMAKE_BINARY_DIR}/file9.sym/file9.txt"
+ "${CMAKE_BINARY_DIR}/file10/file10/file10.txt.sym"
+ DESTINATION "${CMAKE_BINARY_DIR}/dest2"
+ FOLLOW_SYMLINK_CHAIN
+ )
+
+set(resolved_file1.txt.sym file1.txt)
+set(resolved_file10.txt.sym file10.txt)
+set(resolved_file2.txt.sym file2.txt)
+set(resolved_file3.txt.sym file3.txt)
+set(resolved_file4.txt.sym file4.txt)
+set(resolved_file6.txt.sym.1 file6.txt)
+set(resolved_file6.txt.sym.2 file6.txt.sym.1)
+set(resolved_file6.txt.sym.3 file6.txt.sym.2)
+set(resolved_file6.txt.sym.4 file6.txt.sym.3)
+set(resolved_file8.txt.sym file8.txt)
+set(syms)
+foreach(f
+ file1.txt
+ file1.txt.sym
+ file10.txt
+ file10.txt.sym
+ file2.txt
+ file2.txt.sym
+ file3.txt
+ file3.txt.sym
+ file4.txt
+ file4.txt.sym
+ file5.txt
+ file6.txt
+ file6.txt.sym.1
+ file6.txt.sym.2
+ file6.txt.sym.3
+ file6.txt.sym.4
+ file7.txt
+ file8.txt
+ file8.txt.sym
+ file9.txt
+ )
+ string(REPLACE "." "\\." r "${f}")
+ list(APPEND syms "[^;]*/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/dest2/${r}")
+ set(filename "${CMAKE_BINARY_DIR}/dest2/${f}")
+ if(DEFINED resolved_${f})
+ file(READ_SYMLINK "${filename}" resolved)
+ if(NOT resolved STREQUAL "${resolved_${f}}")
+ message(SEND_ERROR "Expected symlink resolution for ${f}: ${resolved_${f}}\nActual resolution: ${resolved}")
+ endif()
+ elseif(NOT EXISTS "${filename}" OR IS_SYMLINK "${filename}" OR IS_DIRECTORY "${filename}")
+ message(SEND_ERROR "${f} should be a regular file")
+ endif()
+endforeach()
+
+file(GLOB_RECURSE actual_syms LIST_DIRECTORIES true "${CMAKE_BINARY_DIR}/dest2/*")
+if(NOT actual_syms MATCHES "^${syms}$")
+ message(SEND_ERROR "Expected files:\n\n ^${syms}$\n\nActual files:\n\n ${actual_syms}")
+endif()
+
+file(INSTALL
+ "${CMAKE_BINARY_DIR}/file1.txt.sym"
+ "${CMAKE_BINARY_DIR}/file2/file2.txt.sym"
+ "${CMAKE_BINARY_DIR}/file3.txt.sym"
+ "${CMAKE_BINARY_DIR}/file4/file4.txt.sym"
+ "${CMAKE_BINARY_DIR}/file5.txt"
+ "${CMAKE_BINARY_DIR}/file6/file6/file6.txt.sym.4"
+ "${CMAKE_BINARY_DIR}/file8/file8.txt.sym"
+ "${CMAKE_BINARY_DIR}/file7/../file7.txt"
+ "${CMAKE_BINARY_DIR}/file8.txt"
+ "${CMAKE_BINARY_DIR}/file9.sym/file9.txt"
+ "${CMAKE_BINARY_DIR}/file10/file10/file10.txt.sym"
+ DESTINATION "${CMAKE_BINARY_DIR}/dest3"
+ )
+
+set(resolved_file1.txt.sym [[^file1\.txt$]])
+set(resolved_file10.txt.sym [[/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/file10/file10/\.\./file10\.txt$]])
+set(resolved_file2.txt.sym [[^\.\./file2\.txt$]])
+set(resolved_file3.txt.sym [[/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/file3\.txt$]])
+set(resolved_file4.txt.sym [[/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/file4\.txt$]])
+set(resolved_file6.txt.sym.4 [[^file6\.txt\.sym\.3$]])
+set(resolved_file8.txt.sym [[/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/file8/\.\./file8\.txt$]])
+set(syms)
+foreach(f
+ file1.txt.sym
+ file10.txt.sym
+ file2.txt.sym
+ file3.txt.sym
+ file4.txt.sym
+ file5.txt
+ file6.txt.sym.4
+ file7.txt
+ file8.txt
+ file8.txt.sym
+ file9.txt
+ )
+ string(REPLACE "." "\\." r "${f}")
+ list(APPEND syms "[^;]*/Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN-build/dest3/${r}")
+ set(filename "${CMAKE_BINARY_DIR}/dest3/${f}")
+ if(DEFINED resolved_${f})
+ file(READ_SYMLINK "${filename}" resolved)
+ if(NOT resolved MATCHES "${resolved_${f}}")
+ message(SEND_ERROR "Expected symlink resolution for ${f}: ${resolved_${f}}\nActual resolution: ${resolved}")
+ endif()
+ elseif(NOT EXISTS "${filename}" OR IS_SYMLINK "${filename}" OR IS_DIRECTORY "${filename}")
+ message(SEND_ERROR "${f} should be a regular file")
+ endif()
+endforeach()
+
+file(GLOB_RECURSE actual_syms LIST_DIRECTORIES true "${CMAKE_BINARY_DIR}/dest3/*")
+if(NOT actual_syms MATCHES "^${syms}$")
+ message(SEND_ERROR "Expected files:\n\n ^${syms}$\n\nActual files:\n\n ${actual_syms}")
+endif()
diff --git a/Tests/RunCMake/file/REMOVE-empty-stderr.txt b/Tests/RunCMake/file/REMOVE-empty-stderr.txt
new file mode 100644
index 000000000..898a6e16e
--- /dev/null
+++ b/Tests/RunCMake/file/REMOVE-empty-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Warning \(dev\) at REMOVE-empty.cmake:1 \(file\):
+ Ignoring empty file name in REMOVE.
+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 REMOVE-empty.cmake:2 \(file\):
+ Ignoring empty file name in REMOVE_RECURSE.
+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/file/REMOVE-empty.cmake b/Tests/RunCMake/file/REMOVE-empty.cmake
new file mode 100644
index 000000000..38046fb51
--- /dev/null
+++ b/Tests/RunCMake/file/REMOVE-empty.cmake
@@ -0,0 +1,2 @@
+file(REMOVE "")
+file(REMOVE_RECURSE "")
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 128e8f383..5db4b3bce 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -43,6 +43,8 @@ run_cmake(GLOB_RECURSE-noexp-FOLLOW_SYMLINKS)
run_cmake(SIZE)
run_cmake(SIZE-error-does-not-exist)
+run_cmake(REMOVE-empty)
+
# tests are valid both for GLOB and GLOB_RECURSE
run_cmake(GLOB-sort-dedup)
run_cmake(GLOB-error-LIST_DIRECTORIES-not-boolean)
@@ -64,6 +66,7 @@ if(NOT WIN32 OR CYGWIN)
run_cmake(READ_SYMLINK)
run_cmake(READ_SYMLINK-noexist)
run_cmake(READ_SYMLINK-notsymlink)
+ run_cmake(INSTALL-FOLLOW_SYMLINK_CHAIN)
endif()
if(RunCMake_GENERATOR STREQUAL "Ninja")
diff --git a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
index c41cb2a75..15335b2a9 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
@@ -4,6 +4,8 @@ if(WIN32)
[[bin/exe\.exe]]
[[bin/(lib)?lib1\.dll]]
[[include]]
+ [[include/obj1\.h]]
+ [[include/obj2\.h]]
[[include/obj4\.h]]
[[include/obj5\.h]]
[[lib]]
@@ -20,6 +22,8 @@ elseif(CYGWIN)
[[bin/cyglib1\.dll]]
[[bin/exe\.exe]]
[[include]]
+ [[include/obj1\.h]]
+ [[include/obj2\.h]]
[[include/obj4\.h]]
[[include/obj5\.h]]
[[lib]]
@@ -35,6 +39,8 @@ else()
[[bin]]
[[bin/exe]]
[[include]]
+ [[include/obj1\.h]]
+ [[include/obj2\.h]]
[[include/obj4\.h]]
[[include/obj5\.h]]
[[lib]]
diff --git a/Tests/RunCMake/install/TARGETS-Defaults.cmake b/Tests/RunCMake/install/TARGETS-Defaults.cmake
index bfd8c2c61..324aa111f 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults.cmake
@@ -8,6 +8,11 @@ set_property(TARGET lib3 PROPERTY PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj
add_library(lib4 SHARED obj5.c)
set_property(TARGET lib4 PROPERTY PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj5.h)
+add_library(iface INTERFACE)
+set_target_properties(iface PROPERTIES
+ PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj1.h
+ PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj2.h)
+
install(TARGETS exe lib1 lib2)
install(TARGETS lib3
LIBRARY DESTINATION lib3
@@ -17,3 +22,6 @@ install(TARGETS lib4
LIBRARY DESTINATION lib4
RUNTIME DESTINATION lib4
)
+install(TARGETS iface
+ PUBLIC_HEADER DESTINATION include
+ PRIVATE_HEADER DESTINATION include)
diff --git a/Tests/RunCMake/install/obj2.h b/Tests/RunCMake/install/obj2.h
new file mode 100644
index 000000000..90bcd3444
--- /dev/null
+++ b/Tests/RunCMake/install/obj2.h
@@ -0,0 +1,6 @@
+#ifndef OBJ2_H
+#define OBJ2_H
+
+int obj2(void);
+
+#endif /* OBJ2_H */
diff --git a/Tests/RunCMake/interface_library/whitelist.cmake b/Tests/RunCMake/interface_library/whitelist.cmake
index bf64f01b0..0db637531 100644
--- a/Tests/RunCMake/interface_library/whitelist.cmake
+++ b/Tests/RunCMake/interface_library/whitelist.cmake
@@ -14,3 +14,12 @@ get_target_property(outname iface "_custom_property")
set_property(TARGET iface PROPERTY "custom_property" output)
set_property(TARGET iface APPEND PROPERTY "custom_property" append)
get_target_property(outname iface "custom_property")
+
+# PUBLIC_HEADER / PRIVATE_HEADER properties are allowed
+set_property(TARGET iface PROPERTY PUBLIC_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PUBLIC_HEADER bar.h)
+get_target_property(outname iface PUBLIC_HEADER)
+
+set_property(TARGET iface PROPERTY PRIVATE_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PRIVATE_HEADER bar.h)
+get_target_property(outname iface PRIVATE_HEADER)
diff --git a/Tests/RunCMake/list/POP_BACK-NoArgs-result.txt b/Tests/RunCMake/list/POP_BACK-NoArgs-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK-NoArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt b/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt
new file mode 100644
index 000000000..83060b44c
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/POP_BACK-NoArgs.cmake b/Tests/RunCMake/list/POP_BACK-NoArgs.cmake
new file mode 100644
index 000000000..518924d71
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK-NoArgs.cmake
@@ -0,0 +1 @@
+list(POP_FRONT)
diff --git a/Tests/RunCMake/list/POP_BACK.cmake b/Tests/RunCMake/list/POP_BACK.cmake
new file mode 100644
index 000000000..479479632
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK.cmake
@@ -0,0 +1,79 @@
+cmake_policy(SET CMP0054 NEW)
+
+function(assert_expected_list_len list_var expected_size)
+ list(LENGTH ${list_var} _size)
+ if(NOT _size EQUAL ${expected_size})
+ message(FATAL_ERROR "list size expected to be `${expected_size}`, got `${_size}` instead")
+ endif()
+endfunction()
+
+# Pop from undefined list
+list(POP_BACK test)
+if(DEFINED test)
+ message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Pop from empty list
+set(test)
+list(POP_BACK test)
+if(DEFINED test)
+ message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Default pop from 1-item list
+list(APPEND test one)
+list(POP_BACK test)
+assert_expected_list_len(test 0)
+
+# Pop from 1-item list to var
+list(APPEND test one)
+list(POP_BACK test one)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+ message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+ message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+
+unset(one)
+unset(two)
+
+# Pop from 1-item list to vars
+list(APPEND test one)
+list(POP_BACK test one two)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+ message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+ message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(DEFINED two)
+ message(FATAL_ERROR "`two` expected to be undefined")
+endif()
+
+unset(one)
+unset(two)
+
+# Default pop from 2-item list
+list(APPEND test one two)
+list(POP_BACK test)
+assert_expected_list_len(test 1)
+if(NOT test STREQUAL "one")
+ message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
+
+# Pop from 2-item list
+list(APPEND test two)
+list(POP_BACK test two)
+assert_expected_list_len(test 1)
+if(NOT DEFINED two)
+ message(FATAL_ERROR "`two` expected to be defined")
+endif()
+if(NOT two STREQUAL "two")
+ message(FATAL_ERROR "`two` has unexpected value `${two}`")
+endif()
+if(NOT test STREQUAL "one")
+ message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
diff --git a/Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt b/Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt b/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt
new file mode 100644
index 000000000..83060b44c
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake b/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake
new file mode 100644
index 000000000..c5cf83739
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake
@@ -0,0 +1 @@
+list(POP_BACK)
diff --git a/Tests/RunCMake/list/POP_FRONT.cmake b/Tests/RunCMake/list/POP_FRONT.cmake
new file mode 100644
index 000000000..70f757a27
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT.cmake
@@ -0,0 +1,92 @@
+cmake_policy(SET CMP0054 NEW)
+
+function(assert_expected_list_len list_var expected_size)
+ list(LENGTH ${list_var} _size)
+ if(NOT _size EQUAL ${expected_size})
+ message(FATAL_ERROR "list size expected to be `${expected_size}`, got `${_size}` instead")
+ endif()
+endfunction()
+
+# Pop from undefined list
+list(POP_FRONT test)
+if(DEFINED test)
+ message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Pop from empty list
+set(test)
+list(POP_FRONT test)
+if(DEFINED test)
+ message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Default pop from 1-item list
+list(APPEND test one)
+list(POP_FRONT test)
+assert_expected_list_len(test 0)
+
+# Pop from 1-item list to var
+list(APPEND test one)
+list(POP_FRONT test one)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+ message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+ message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+
+unset(one)
+unset(two)
+
+# Pop from 1-item list to vars
+list(APPEND test one)
+list(POP_FRONT test one two)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+ message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+ message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(DEFINED two)
+ message(FATAL_ERROR "`two` expected to be undefined")
+endif()
+
+unset(one)
+unset(two)
+
+# Default pop from 2-item list
+list(APPEND test one two)
+list(POP_FRONT test)
+assert_expected_list_len(test 1)
+if(NOT test STREQUAL "two")
+ message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
+
+# Pop from 2-item list
+list(PREPEND test one)
+list(POP_FRONT test one)
+assert_expected_list_len(test 1)
+if(NOT DEFINED one)
+ message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+ message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(NOT test STREQUAL "two")
+ message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
+
+# BUG 19436
+set(myList a b c)
+list(POP_FRONT myList first second)
+if(NOT first STREQUAL "a")
+ message(FATAL_ERROR "BUG#19436: `first` has unexpected value `${first}`")
+endif()
+if(NOT second STREQUAL "b")
+ message(FATAL_ERROR "BUG#19436: `second` has unexpected value `${second}`")
+endif()
+if(NOT myList STREQUAL "c")
+ message(FATAL_ERROR "BUG#19436: `myList` has unexpected value `${myList}`")
+endif()
diff --git a/Tests/RunCMake/list/PREPEND-NoArgs-result.txt b/Tests/RunCMake/list/PREPEND-NoArgs-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND-NoArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt b/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt
new file mode 100644
index 000000000..83060b44c
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/PREPEND-NoArgs.cmake b/Tests/RunCMake/list/PREPEND-NoArgs.cmake
new file mode 100644
index 000000000..8935fa9c5
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND-NoArgs.cmake
@@ -0,0 +1 @@
+list(PREPEND)
diff --git a/Tests/RunCMake/list/PREPEND.cmake b/Tests/RunCMake/list/PREPEND.cmake
new file mode 100644
index 000000000..17b292126
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND.cmake
@@ -0,0 +1,33 @@
+list(PREPEND test)
+if(test)
+ message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test satu)
+if(NOT test STREQUAL "satu")
+ message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test dua)
+if(NOT test STREQUAL "dua;satu")
+ message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test tiga)
+if(NOT test STREQUAL "tiga;dua;satu")
+ message(FATAL_ERROR "failed")
+endif()
+
+# Scope test
+function(foo)
+ list(PREPEND test empat)
+ if(NOT test STREQUAL "empat;tiga;dua;satu")
+ message(FATAL_ERROR "failed")
+ endif()
+endfunction()
+
+foo()
+
+if(NOT test STREQUAL "tiga;dua;satu")
+ message(FATAL_ERROR "failed")
+endif()
diff --git a/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake b/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake
new file mode 100644
index 000000000..91abbd61a
--- /dev/null
+++ b/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake
@@ -0,0 +1,5 @@
+set(mylist "b;c;b;a;a;c;b;a;c;b")
+list(REMOVE_DUPLICATES mylist)
+if(NOT mylist STREQUAL "b;c;a")
+ message(SEND_ERROR "Expected b;c;a, got ${mylist}")
+endif()
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index bf3d22db4..b4a91bc62 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -24,6 +24,8 @@ run_cmake(SUBLIST-TooManyArguments)
run_cmake(REMOVE_AT-EmptyList)
+run_cmake(REMOVE_DUPLICATES-PreserveOrder)
+
run_cmake(FILTER-NotList)
run_cmake(REMOVE_AT-NotList)
run_cmake(REMOVE_DUPLICATES-NotList)
@@ -98,3 +100,15 @@ run_cmake(SORT-NoCaseOption)
# Successful tests
run_cmake(SORT)
+
+# argument tests
+run_cmake(PREPEND-NoArgs)
+# Successful tests
+run_cmake(PREPEND)
+
+# argument tests
+run_cmake(POP_BACK-NoArgs)
+run_cmake(POP_FRONT-NoArgs)
+# Successful tests
+run_cmake(POP_BACK)
+run_cmake(POP_FRONT)
diff --git a/Tests/RunCMake/message/RunCMakeTest.cmake b/Tests/RunCMake/message/RunCMakeTest.cmake
index 24dad039e..cecfc7fe5 100644
--- a/Tests/RunCMake/message/RunCMakeTest.cmake
+++ b/Tests/RunCMake/message/RunCMakeTest.cmake
@@ -10,3 +10,45 @@ run_cmake(warnmessage)
# separately
run_cmake(errormessage_deprecated)
run_cmake(errormessage_dev)
+
+run_cmake_command(
+ message-loglevel-invalid
+ ${CMAKE_COMMAND} --loglevel=blah -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+
+# Checking various combinations of `message(...)` and log levels `WARNING` to `TRACE`
+# - no CLI option -> `WARNING` to `STATUS` output
+run_cmake_command(
+ message-loglevel-default
+ ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - Only `WARNING` output
+run_cmake_command(
+ message-loglevel-warning
+ ${CMAKE_COMMAND} --loglevel=warning -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - Only `WARNING` and `NOTICE` output
+run_cmake_command(
+ message-loglevel-notice
+ ${CMAKE_COMMAND} --loglevel=notice -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - `WARNING` to `STATUS` output
+run_cmake_command(
+ message-loglevel-status
+ ${CMAKE_COMMAND} --loglevel=status -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - `WARNING` to `VERBOSE` output
+run_cmake_command(
+ message-loglevel-verbose
+ ${CMAKE_COMMAND} --loglevel=verbose -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - `WARNING` to `DEBUG` output
+run_cmake_command(
+ message-loglevel-debug
+ ${CMAKE_COMMAND} --loglevel=debug -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
+# - `WARNING` to `TRACE` output
+run_cmake_command(
+ message-loglevel-trace
+ ${CMAKE_COMMAND} --loglevel=trace -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+ )
diff --git a/Tests/RunCMake/message/message-all-loglevels.cmake b/Tests/RunCMake/message/message-all-loglevels.cmake
new file mode 100644
index 000000000..f8d884154
--- /dev/null
+++ b/Tests/RunCMake/message/message-all-loglevels.cmake
@@ -0,0 +1,10 @@
+# Produce a message for everything except FATAL_ERROR and SEND_ERROR
+message(DEPRECATION "Deprecation warning")
+message(AUTHOR_WARNING "Author warning message")
+message(WARNING "Warning message")
+message("Default NOTICE message")
+message(NOTICE "NOTICE message")
+message(STATUS "STATUS message")
+message(VERBOSE "VERBOSE message")
+message(DEBUG "DEBUG message")
+message(TRACE "TRACE message")
diff --git a/Tests/RunCMake/message/message-loglevel-debug-stderr.txt b/Tests/RunCMake/message/message-loglevel-debug-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-debug-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-debug-stdout.txt b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt
new file mode 100644
index 000000000..145213703
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt
@@ -0,0 +1,3 @@
+-- STATUS message
+-- VERBOSE message
+-- DEBUG message
diff --git a/Tests/RunCMake/message/message-loglevel-default-stderr.txt b/Tests/RunCMake/message/message-loglevel-default-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-default-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-default-stdout.txt b/Tests/RunCMake/message/message-loglevel-default-stdout.txt
new file mode 100644
index 000000000..809f4cc4a
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-default-stdout.txt
@@ -0,0 +1 @@
+-- STATUS message
diff --git a/Tests/RunCMake/message/message-loglevel-invalid-result.txt b/Tests/RunCMake/message/message-loglevel-invalid-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt b/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt
new file mode 100644
index 000000000..f54d0f844
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt
@@ -0,0 +1 @@
+CMake Error: Invalid level specified for --loglevel
diff --git a/Tests/RunCMake/message/message-loglevel-notice-stderr.txt b/Tests/RunCMake/message/message-loglevel-notice-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-notice-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-status-stderr.txt b/Tests/RunCMake/message/message-loglevel-status-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-status-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-status-stdout.txt b/Tests/RunCMake/message/message-loglevel-status-stdout.txt
new file mode 100644
index 000000000..809f4cc4a
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-status-stdout.txt
@@ -0,0 +1 @@
+-- STATUS message
diff --git a/Tests/RunCMake/message/message-loglevel-trace-stderr.txt b/Tests/RunCMake/message/message-loglevel-trace-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-trace-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-trace-stdout.txt b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt
new file mode 100644
index 000000000..1cfce6f11
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt
@@ -0,0 +1,4 @@
+-- STATUS message
+-- VERBOSE message
+-- DEBUG message
+-- TRACE message
diff --git a/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt b/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt
new file mode 100644
index 000000000..efec736fe
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt
new file mode 100644
index 000000000..c15d43fc4
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt
@@ -0,0 +1,2 @@
+-- STATUS message
+-- VERBOSE message
diff --git a/Tests/RunCMake/message/message-loglevel-warning-stderr.txt b/Tests/RunCMake/message/message-loglevel-warning-stderr.txt
new file mode 100644
index 000000000..c721b063c
--- /dev/null
+++ b/Tests/RunCMake/message/message-loglevel-warning-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+ Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+ Author warning message
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+ Warning message$
diff --git a/Tests/RunCMake/project_injected/CMP0048-WARN-stderr.txt b/Tests/RunCMake/project_injected/CMP0048-WARN-stderr.txt
new file mode 100644
index 000000000..fc1a02b43
--- /dev/null
+++ b/Tests/RunCMake/project_injected/CMP0048-WARN-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Warning \(dev\) in CMakeLists.txt:
+ No project\(\) command is present. The top-level CMakeLists.txt file must
+ contain a literal, direct call to the project\(\) command. Add a line of
+ code such as
+
+ project\(ProjectName\)
+
+ near the top of the file, but after cmake_minimum_required\(\).
+
+ CMake is pretending there is a "project\(Project\)" command on the first
+ line.
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/pseudo_emulator_custom_command_arg.c b/Tests/RunCMake/pseudo_emulator_custom_command_arg.c
new file mode 100644
index 000000000..d00deda53
--- /dev/null
+++ b/Tests/RunCMake/pseudo_emulator_custom_command_arg.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Usage:
+//
+// /path/to/program arg1 [arg2 [...]]
+//
+// Return EXIT_SUCCESS if 'custom_argument' string was found
+// in <arg1> and 'generated_exe_emulator_expected'
+// string was found in <arg2>
+// Return EXIT_FAILURE if 'custom_argument' string was not
+// found in <arg1> or 'generated_exe_emulator_expected'
+// string was not found in <arg2>.
+
+int main(int argc, const char* argv[])
+{
+ // Require a slash to make sure it is a path and not a target name.
+ const char* substring_success = "/generated_exe_emulator_expected";
+ const char* substring_custom_argument = "custom_argument";
+
+ if (argc < 2) {
+ return EXIT_FAILURE;
+ }
+ if (strstr(argv[1], substring_custom_argument) != 0 &&
+ strstr(argv[2], substring_success) != 0) {
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/Tests/RunCMake/string/Repeat.cmake b/Tests/RunCMake/string/Repeat.cmake
new file mode 100644
index 000000000..fc390aa62
--- /dev/null
+++ b/Tests/RunCMake/string/Repeat.cmake
@@ -0,0 +1,45 @@
+string(REPEAT "q" 4 q_out)
+
+if(NOT DEFINED q_out)
+ message(FATAL_ERROR "q_out is not defined")
+endif()
+
+if(NOT q_out STREQUAL "qqqq")
+ message(FATAL_ERROR "unexpected result")
+endif()
+
+string(REPEAT "1234" 0 zero_out)
+
+if(NOT DEFINED zero_out)
+ message(FATAL_ERROR "zero_out is not defined")
+endif()
+
+if(NOT zero_out STREQUAL "")
+ message(FATAL_ERROR "unexpected result")
+endif()
+
+unset(zero_out)
+
+string(REPEAT "" 100 zero_out)
+
+if(NOT DEFINED zero_out)
+ message(FATAL_ERROR "zero_out is not defined")
+endif()
+
+if(NOT zero_out STREQUAL "")
+ message(FATAL_ERROR "unexpected result")
+endif()
+
+string(REPEAT "1" 1 one_out)
+
+if(NOT one_out STREQUAL "1")
+ message(FATAL_ERROR "unexpected result")
+endif()
+
+unset(one_out)
+
+string(REPEAT "one" 1 one_out)
+
+if(NOT one_out STREQUAL "one")
+ message(FATAL_ERROR "unexpected result")
+endif()
diff --git a/Tests/RunCMake/string/RepeatNegativeCount-result.txt b/Tests/RunCMake/string/RepeatNegativeCount-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNegativeCount-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt b/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt
new file mode 100644
index 000000000..bbd498eee
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at RepeatNegativeCount.cmake:[0-9]+ \(string\):
+ repeat count is not a positive number.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/string/RepeatNegativeCount.cmake b/Tests/RunCMake/string/RepeatNegativeCount.cmake
new file mode 100644
index 000000000..769e7c0a1
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNegativeCount.cmake
@@ -0,0 +1 @@
+string(REPEAT "blah" -1 out)
diff --git a/Tests/RunCMake/string/RepeatNoArgs-result.txt b/Tests/RunCMake/string/RepeatNoArgs-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNoArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/string/RepeatNoArgs-stderr.txt b/Tests/RunCMake/string/RepeatNoArgs-stderr.txt
new file mode 100644
index 000000000..5abcb3be7
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNoArgs-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at RepeatNoArgs.cmake:[0-9]+ \(string\):
+ sub-command REPEAT requires three arguments.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/string/RepeatNoArgs.cmake b/Tests/RunCMake/string/RepeatNoArgs.cmake
new file mode 100644
index 000000000..e327e998e
--- /dev/null
+++ b/Tests/RunCMake/string/RepeatNoArgs.cmake
@@ -0,0 +1 @@
+string(REPEAT)
diff --git a/Tests/RunCMake/string/RunCMakeTest.cmake b/Tests/RunCMake/string/RunCMakeTest.cmake
index 211337aa5..c432b4ed5 100644
--- a/Tests/RunCMake/string/RunCMakeTest.cmake
+++ b/Tests/RunCMake/string/RunCMakeTest.cmake
@@ -33,3 +33,7 @@ run_cmake(UTF-16BE)
run_cmake(UTF-16LE)
run_cmake(UTF-32BE)
run_cmake(UTF-32LE)
+
+run_cmake(Repeat)
+run_cmake(RepeatNoArgs)
+run_cmake(RepeatNegativeCount)
diff --git a/Tests/RunCMake/try_compile/CMP0066-stderr.txt b/Tests/RunCMake/try_compile/CMP0066-stderr.txt
index b14e2900e..0b92dcfc7 100644
--- a/Tests/RunCMake/try_compile/CMP0066-stderr.txt
+++ b/Tests/RunCMake/try_compile/CMP0066-stderr.txt
@@ -12,4 +12,15 @@ CMake Warning \(dev\) at CMP0066.cmake:[0-9]+ \(try_compile\):
test project.
Call Stack \(most recent call first\):
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 CMP0066.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0066 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/try_compile/LinkOptions.cmake b/Tests/RunCMake/try_compile/LinkOptions.cmake
index 9b246c400..7fae35ca9 100644
--- a/Tests/RunCMake/try_compile/LinkOptions.cmake
+++ b/Tests/RunCMake/try_compile/LinkOptions.cmake
@@ -5,7 +5,9 @@ cmake_policy(SET CMP0054 NEW)
set (lib_name "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}lib${CMAKE_STATIC_LIBRARY_SUFFIX}")
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
- if (RunCMake_C_COMPILER_ID STREQUAL "MSVC")
+ if (RunCMake_C_COMPILER_ID STREQUAL "MSVC"
+ OR ("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" AND
+ NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"))
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set (undef_flag /INCLUDE:_func)
else()
diff --git a/Tests/RunCMake/try_run/LinkOptions.cmake b/Tests/RunCMake/try_run/LinkOptions.cmake
index 17af2f7d9..b9a87f3ca 100644
--- a/Tests/RunCMake/try_run/LinkOptions.cmake
+++ b/Tests/RunCMake/try_run/LinkOptions.cmake
@@ -5,7 +5,9 @@ cmake_policy(SET CMP0054 NEW)
set (lib_name "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}lib${CMAKE_STATIC_LIBRARY_SUFFIX}")
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
- if (RunCMake_C_COMPILER_ID STREQUAL "MSVC")
+ if (RunCMake_C_COMPILER_ID STREQUAL "MSVC"
+ OR ("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" AND
+ NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"))
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set (undef_flag /INCLUDE:_func)
else()
diff --git a/Tests/SourceGroups/CMakeLists.txt b/Tests/SourceGroups/CMakeLists.txt
index 813774d6a..a5740bba9 100644
--- a/Tests/SourceGroups/CMakeLists.txt
+++ b/Tests/SourceGroups/CMakeLists.txt
@@ -42,8 +42,16 @@ set(tree_files_with_prefix ${root}/tree_prefix_foo.c
set(tree_files_with_empty_prefix ${root}/tree_empty_prefix_foo.c
tree_empty_prefix_bar.c)
+set(tree_files_which_are_actually_directories ${root}
+ ${root}/
+ ${root}/sub1
+ ${root}/sub1/)
+
source_group(TREE ${root} FILES ${tree_files_without_prefix})
+# Should not crash and not add any files - just silently ignore the directories
+source_group(TREE ${root} FILES ${tree_files_which_are_actually_directories})
+
source_group(FILES ${tree_files_with_prefix} PREFIX tree_root/subgroup TREE ${root})
source_group(PREFIX "" FILES ${tree_files_with_empty_prefix} TREE ${root})
diff --git a/Tests/StagingPrefix/CMakeLists.txt b/Tests/StagingPrefix/CMakeLists.txt
index 64a3cd229..8d2519ea3 100644
--- a/Tests/StagingPrefix/CMakeLists.txt
+++ b/Tests/StagingPrefix/CMakeLists.txt
@@ -5,11 +5,12 @@ project(StagingPrefix)
# Wipe out the install tree
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/CleanupProject
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ConsumerBuild
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ProducerBuild
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/stage
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/prefix
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ignored
+ COMMAND ${CMAKE_COMMAND} -E remove_directory
+ ${CMAKE_BINARY_DIR}/ConsumerBuild
+ ${CMAKE_BINARY_DIR}/ProducerBuild
+ ${CMAKE_BINARY_DIR}/stage
+ ${CMAKE_BINARY_DIR}/prefix
+ ${CMAKE_BINARY_DIR}/ignored
)
add_custom_target(CleanupTarget ALL DEPENDS ${CMAKE_BINARY_DIR}/CleanupProject)
set_property(
diff --git a/Tests/SwiftMix/CMain.c b/Tests/SwiftMix/CMain.c
index 8877da430..519058efe 100644
--- a/Tests/SwiftMix/CMain.c
+++ b/Tests/SwiftMix/CMain.c
@@ -1,5 +1,5 @@
-extern int ObjCMain(int argc, char const* const argv[]);
-int main(int argc, char* argv[])
+extern int ObjCMain(void);
+int main(void)
{
- return ObjCMain(argc, argv);
+ return ObjCMain();
}
diff --git a/Tests/SwiftMix/CMakeLists.txt b/Tests/SwiftMix/CMakeLists.txt
index 5e50470f6..6d8e48bd0 100644
--- a/Tests/SwiftMix/CMakeLists.txt
+++ b/Tests/SwiftMix/CMakeLists.txt
@@ -3,3 +3,4 @@ project(SwiftMix C Swift)
add_executable(SwiftMix CMain.c ObjCMain.m SwiftMain.swift ObjC-Swift.h)
set_property(TARGET SwiftMix PROPERTY XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "ObjC-Swift.h")
+target_compile_options(SwiftMix PRIVATE "$<$<COMPILE_LANGUAGE:C>:-Werror=objc-method-access>")
diff --git a/Tests/SwiftMix/ObjCMain.m b/Tests/SwiftMix/ObjCMain.m
index 20f0bf1ee..afc924380 100644
--- a/Tests/SwiftMix/ObjCMain.m
+++ b/Tests/SwiftMix/ObjCMain.m
@@ -1,4 +1,4 @@
#import "SwiftMix-Swift.h"
-int ObjCMain(int argc, char const* const argv[]) {
+int ObjCMain(void) {
return [SwiftMainClass SwiftMain];
}
diff --git a/Tests/SwiftMix/SwiftMain.swift b/Tests/SwiftMix/SwiftMain.swift
index a4a0a62b4..d9c8cd756 100644
--- a/Tests/SwiftMix/SwiftMain.swift
+++ b/Tests/SwiftMix/SwiftMain.swift
@@ -1,7 +1,7 @@
import Foundation
@objc class SwiftMainClass : NSObject {
- class func SwiftMain() -> Int32 {
+ @objc class func SwiftMain() -> Int32 {
dump("Hello World!");
return 0;
}
diff --git a/Tests/Tutorial/Complete/CMakeLists.txt b/Tests/Tutorial/Complete/CMakeLists.txt
index 9658e6536..1c97545e4 100644
--- a/Tests/Tutorial/Complete/CMakeLists.txt
+++ b/Tests/Tutorial/Complete/CMakeLists.txt
@@ -7,8 +7,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
diff --git a/Tests/Tutorial/Consumer/CMakeLists.txt b/Tests/Tutorial/Consumer/CMakeLists.txt
index 4033b4da8..50979177e 100644
--- a/Tests/Tutorial/Consumer/CMakeLists.txt
+++ b/Tests/Tutorial/Consumer/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
if(NOT DEFINED CMAKE_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD 11)
- set(CMAKE_CXX_STANDARD_REQUIRED True)
+ set(CMAKE_CXX_STANDARD 14)
endif()
diff --git a/Tests/Tutorial/Step10/CMakeLists.txt b/Tests/Tutorial/Step10/CMakeLists.txt
index b1d46c4b9..79aadd5d6 100644
--- a/Tests/Tutorial/Step10/CMakeLists.txt
+++ b/Tests/Tutorial/Step10/CMakeLists.txt
@@ -7,8 +7,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
diff --git a/Tests/Tutorial/Step11/CMakeLists.txt b/Tests/Tutorial/Step11/CMakeLists.txt
index b1d46c4b9..79aadd5d6 100644
--- a/Tests/Tutorial/Step11/CMakeLists.txt
+++ b/Tests/Tutorial/Step11/CMakeLists.txt
@@ -7,8 +7,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
diff --git a/Tests/Tutorial/Step2/CMakeLists.txt b/Tests/Tutorial/Step2/CMakeLists.txt
index 48afaa327..8e50e7c20 100644
--- a/Tests/Tutorial/Step2/CMakeLists.txt
+++ b/Tests/Tutorial/Step2/CMakeLists.txt
@@ -1,9 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
-
+set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
diff --git a/Tests/Tutorial/Step2/directions.txt b/Tests/Tutorial/Step2/directions.txt
index bb6662c7e..48de7a2f1 100644
--- a/Tests/Tutorial/Step2/directions.txt
+++ b/Tests/Tutorial/Step2/directions.txt
@@ -44,8 +44,7 @@ the following:
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
- set(CMAKE_CXX_STANDARD 11)
- set(CMAKE_CXX_STANDARD_REQUIRED True)
+ set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
diff --git a/Tests/Tutorial/Step3/CMakeLists.txt b/Tests/Tutorial/Step3/CMakeLists.txt
index f904ea748..baa0a4440 100644
--- a/Tests/Tutorial/Step3/CMakeLists.txt
+++ b/Tests/Tutorial/Step3/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
diff --git a/Tests/Tutorial/Step4/CMakeLists.txt b/Tests/Tutorial/Step4/CMakeLists.txt
index 34eab5558..9ce60b91c 100644
--- a/Tests/Tutorial/Step4/CMakeLists.txt
+++ b/Tests/Tutorial/Step4/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
diff --git a/Tests/Tutorial/Step5/CMakeLists.txt b/Tests/Tutorial/Step5/CMakeLists.txt
index 63e541056..828b9fc97 100644
--- a/Tests/Tutorial/Step5/CMakeLists.txt
+++ b/Tests/Tutorial/Step5/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
diff --git a/Tests/Tutorial/Step6/CMakeLists.txt b/Tests/Tutorial/Step6/CMakeLists.txt
index 503a31290..a78b0ff76 100644
--- a/Tests/Tutorial/Step6/CMakeLists.txt
+++ b/Tests/Tutorial/Step6/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
diff --git a/Tests/Tutorial/Step7/CMakeLists.txt b/Tests/Tutorial/Step7/CMakeLists.txt
index f2d3839b7..33aa0396c 100644
--- a/Tests/Tutorial/Step7/CMakeLists.txt
+++ b/Tests/Tutorial/Step7/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
diff --git a/Tests/Tutorial/Step8/CMakeLists.txt b/Tests/Tutorial/Step8/CMakeLists.txt
index c66bf96e3..03dc7c0f6 100644
--- a/Tests/Tutorial/Step8/CMakeLists.txt
+++ b/Tests/Tutorial/Step8/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
diff --git a/Tests/Tutorial/Step9/CMakeLists.txt b/Tests/Tutorial/Step9/CMakeLists.txt
index 309d513ff..4981fe20f 100644
--- a/Tests/Tutorial/Step9/CMakeLists.txt
+++ b/Tests/Tutorial/Step9/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
diff --git a/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt b/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt
new file mode 100644
index 000000000..a2c239cbd
--- /dev/null
+++ b/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.14...3.15)
+
+project(TestAlternateLibraryName CXX)
+
+include(CTest)
+
+find_package(SWIG REQUIRED)
+include(${SWIG_USE_FILE})
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+
+# Path separator
+if (WIN32)
+ set (PS "$<SEMICOLON>")
+else()
+ set (PS ":")
+endif()
+
+unset(CMAKE_SWIG_FLAGS)
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/../example.i" PROPERTY CPLUSPLUS ON)
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/../example.i" PROPERTY COMPILE_OPTIONS -includeall)
+
+swig_add_library(example_python
+ LANGUAGE python
+ SOURCES ../example.i ../example.cxx)
+set_target_properties (example_python PROPERTIES
+ INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/.."
+ SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)
+target_link_libraries(example_python PRIVATE Python2::Python)
+
+
+add_test (NAME AlternateLibraryName.example1
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}${PS}$<TARGET_FILE_DIR:example_python>"
+ "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
diff --git a/Tests/UseSWIG/CMakeLists.txt b/Tests/UseSWIG/CMakeLists.txt
index 434895e1b..3cc910fec 100644
--- a/Tests/UseSWIG/CMakeLists.txt
+++ b/Tests/UseSWIG/CMakeLists.txt
@@ -123,3 +123,15 @@ add_test(NAME UseSWIG.SwigSrcFileExtension COMMAND
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+
+
+add_test(NAME UseSWIG.AlternateLibraryName COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/UseSWIG/AlternateLibraryName"
+ "${CMake_BINARY_DIR}/Tests/UseSWIG/AlternateLibraryName"
+ ${build_generator_args}
+ --build-project TestAlternateLibraryName
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/UseSWIG/ModuleName/CMakeLists.txt b/Tests/UseSWIG/ModuleName/CMakeLists.txt
index de6388335..435b441a4 100644
--- a/Tests/UseSWIG/ModuleName/CMakeLists.txt
+++ b/Tests/UseSWIG/ModuleName/CMakeLists.txt
@@ -34,7 +34,7 @@ set_target_properties (example1 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1")
-target_link_libraries(example1 PRIVATE Python2::Python)
+target_link_libraries(example1 PRIVATE Python2::Module)
add_test (NAME ModuleName.example1
diff --git a/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt b/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
index a7ee2106b..093e8582c 100644
--- a/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
+++ b/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
@@ -33,7 +33,7 @@ set_target_properties (example1 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2")
-target_link_libraries(example1 PRIVATE Python2::Python)
+target_link_libraries(example1 PRIVATE Python2::Module)
# re-use sample interface file for another plugin
swig_add_library(example2
@@ -44,7 +44,7 @@ set_target_properties (example2 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3")
-target_link_libraries(example2 PRIVATE Python3::Python)
+target_link_libraries(example2 PRIVATE Python3::Module)
add_test (NAME ModuleVersion2.example1
diff --git a/Tests/UseSWIG/MultipleModules/CMakeLists.txt b/Tests/UseSWIG/MultipleModules/CMakeLists.txt
index f1dc379c5..4380080f5 100644
--- a/Tests/UseSWIG/MultipleModules/CMakeLists.txt
+++ b/Tests/UseSWIG/MultipleModules/CMakeLists.txt
@@ -36,7 +36,7 @@ set_target_properties (example1 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python")
-target_link_libraries(example1 PRIVATE Python::Python)
+target_link_libraries(example1 PRIVATE Python::Module)
# re-use sample interface file for another plugin
set_property(SOURCE "../example.i" APPEND PROPERTY
diff --git a/Tests/UseSWIG/MultiplePython/CMakeLists.txt b/Tests/UseSWIG/MultiplePython/CMakeLists.txt
index 8f8775576..cf6c80e28 100644
--- a/Tests/UseSWIG/MultiplePython/CMakeLists.txt
+++ b/Tests/UseSWIG/MultiplePython/CMakeLists.txt
@@ -34,7 +34,7 @@ set_target_properties (example1 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2")
-target_link_libraries(example1 PRIVATE Python2::Python)
+target_link_libraries(example1 PRIVATE Python2::Module)
# re-use sample interface file for another plugin
swig_add_library(example2
@@ -46,7 +46,7 @@ set_target_properties (example2 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3")
-target_link_libraries(example2 PRIVATE Python3::Python)
+target_link_libraries(example2 PRIVATE Python3::Module)
diff --git a/Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt b/Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt
index 7eb73d42b..f70ce491d 100644
--- a/Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt
+++ b/Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt
@@ -16,11 +16,11 @@ set(SWIG_SOURCE_FILE_EXTENSIONS ".i" ".swg")
# Generate a Python module out of `.i`
swig_add_library(my_add LANGUAGE python SOURCES my_add.i)
-target_link_libraries(my_add Python::Python)
+target_link_libraries(my_add Python::Module)
# Generate a Python module out of `.swg`
swig_add_library(my_sub LANGUAGE python SOURCES my_sub.swg)
-target_link_libraries(my_sub Python::Python)
+target_link_libraries(my_sub Python::Module)
# Add a test
add_test(NAME SwigSrcFileExtension
diff --git a/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt b/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
index fbb72d571..80a2e1650 100644
--- a/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
+++ b/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
@@ -25,7 +25,7 @@ set_target_properties (example1 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1")
-target_link_libraries(example1 PRIVATE Python3::Python)
+target_link_libraries(example1 PRIVATE Python3::Module)
# Check that source property override target property
@@ -42,4 +42,4 @@ set_target_properties (example2 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2")
-target_link_libraries(example2 PRIVATE Python3::Python)
+target_link_libraries(example2 PRIVATE Python3::Module)
diff --git a/Tests/WarnUnusedCliUnused/CMakeLists.txt b/Tests/WarnUnusedCliUnused/CMakeLists.txt
index 7ed69bf3c..a149f043f 100644
--- a/Tests/WarnUnusedCliUnused/CMakeLists.txt
+++ b/Tests/WarnUnusedCliUnused/CMakeLists.txt
@@ -1,9 +1,9 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.14)
project(WarnUnusedCliUnused)
-set_directory_properties(PROPERTIES
- ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_BINARY_DIR}/CMakeCache.txt"
-)
+# Remove UNUSED_CLI_VARIABLE from the cache to trigger the
+# CMake warning message on re-builds as well.
+unset(UNUSED_CLI_VARIABLE CACHE)
add_library(dummy empty.cpp)
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 2cdd7672d..ce4cfaf4b 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeDeveloperReference_STANDALONE 1)
- cmake_minimum_required(VERSION 3.1...3.12 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.1...3.14 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)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 482a08dd8..0393ff199 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -68,6 +68,7 @@
{ symbol: [ "std::__decay_and_strip<cmGeneratorTarget *&>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmFindCommon::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmSearchPath>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<cm::string_view>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<const std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake
index fa585d74b..958ed2544 100644
--- a/Utilities/Release/linux64_release.cmake
+++ b/Utilities/Release/linux64_release.cmake
@@ -44,6 +44,7 @@ CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=${qt_xcb_libs}
set(ENV [[
export CMAKE_PREFIX_PATH=/opt/binutils-2.31
]])
+set(SIGN "")
# Exclude Qt5 tests because our Qt5 is static.
set(EXTRA_CTEST_ARGS "-E Qt5")
diff --git a/Utilities/Release/osx_release.cmake b/Utilities/Release/osx_release.cmake
index be11d470b..ac35872ea 100644
--- a/Utilities/Release/osx_release.cmake
+++ b/Utilities/Release/osx_release.cmake
@@ -29,5 +29,6 @@ CMake_TEST_NO_FindPackageModeMakefileTest:BOOL=TRUE
set(ENV [[
export CMAKE_PREFIX_PATH='/Users/kitware/SDKs/qt-5.6.2-clang-x64'
]])
+set(SIGN "")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/push.bash b/Utilities/Release/push.bash
new file mode 100755
index 000000000..1c8efe900
--- /dev/null
+++ b/Utilities/Release/push.bash
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+usage='usage: push.bash [<options>] [--] <dest>
+
+Options:
+
+ --dir <dir> Specify subdirectory under destination.
+ Defaults to "v<version>".
+ --version <ver> CMake <major>.<minor> version number to push.
+ Defaults to version of source tree.
+'
+
+die() {
+ echo "$@" 1>&2; exit 1
+}
+
+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=''
+dir=''
+while test "$#" != 0; do
+ case "$1" in
+ --dir) shift; dir="$1" ;;
+ --version) shift; version="$1" ;;
+ --) shift ; break ;;
+ -*) die "$usage" ;;
+ *) break ;;
+ esac
+ shift
+done
+test "$#" = 1 || die "$usage"
+readonly dest="$1"
+
+if test -z "$version"; then
+ cmake_version_major="$(cmake_version_component MAJOR)"
+ cmake_version_minor="$(cmake_version_component MINOR)"
+ version="${cmake_version_major}.${cmake_version_minor}"
+fi
+readonly version
+
+if test -z "$dir"; then
+ dir="v${version}"
+fi
+readonly dir
+
+for f in cmake-${version}*; do
+ if ! test -f "${f}"; then
+ continue
+ fi
+
+ echo "pushing '${f}'"
+
+ # Make a copy with a new timestamp and atomically rename into place.
+ tf="${dest}/${dir}/.tmp.${f}"
+ df="${dest}/${dir}/${f}"
+ cp "${f}" "${tf}"
+ mv "${tf}" "${df}"
+
+ # Pause to give each file a distinct time stamp even with 1s resolution
+ # so that sorting by time also sorts alphabetically.
+ sleep 1.1
+done
diff --git a/Utilities/Release/release_cmake.sh.in b/Utilities/Release/release_cmake.sh.in
index f363b3d8a..696a3f445 100755
--- a/Utilities/Release/release_cmake.sh.in
+++ b/Utilities/Release/release_cmake.sh.in
@@ -150,7 +150,7 @@ for GEN in $generators; do
check_exit_value $? "Create $GEN package" || exit 1
done
-
+@SIGN@
echo "End release"
date
diff --git a/Utilities/Release/upload_release.cmake b/Utilities/Release/upload_release.cmake
deleted file mode 100644
index 3613ae7a7..000000000
--- a/Utilities/Release/upload_release.cmake
+++ /dev/null
@@ -1,39 +0,0 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-if(NOT VERSION)
- set(VERSION 3.14)
-endif()
-if(NOT DEFINED PROJECT_PREFIX)
- set(PROJECT_PREFIX cmake-${VERSION})
-endif()
-if(NOT DEFINED DIR)
- set(DIR "v${VERSION}")
-endif()
-file(GLOB FILES ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_PREFIX}*")
-list(SORT FILES)
-list(REVERSE FILES)
-message("${FILES}")
-set(UPLOAD_LOC
- "kitware@www.cmake.org:/projects/FTP/pub/cmake/${DIR}")
-set(count 0)
-foreach(file ${FILES})
- if(NOT IS_DIRECTORY ${file})
- message("upload ${file} ${UPLOAD_LOC}")
- execute_process(COMMAND
- scp ${file} ${UPLOAD_LOC}
- RESULT_VARIABLE result)
- if("${result}" GREATER 0)
- message(FATAL_ERROR "failed to upload file to ${UPLOAD_LOC}")
- endif()
-
- # Pause to give each upload a distinct (to the nearest second)
- # time stamp
- if(COMMAND ctest_sleep)
- ctest_sleep(2)
- endif()
-
- math(EXPR count "${count} + 1")
- endif()
-endforeach()
-if(${count} EQUAL 0)
- message(FATAL_ERROR "Error no files uploaded.")
-endif()
diff --git a/Utilities/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake
index c03c66550..468e5f437 100644
--- a/Utilities/Release/win32_release.cmake
+++ b/Utilities/Release/win32_release.cmake
@@ -8,12 +8,17 @@ set(CPACK_BINARY_GENERATORS "WIX ZIP")
set(CPACK_SOURCE_GENERATORS "ZIP")
set(MAKE_PROGRAM "ninja")
set(MAKE "${MAKE_PROGRAM} -j16")
-set(qt_prefix "c:/Qt/5.6.3/msvc2017-32-xp-mt")
+set(qt_prefix "c:/Qt/5.12.1/msvc2017-32-w7-mt")
set(qt_win_libs
${qt_prefix}/plugins/platforms/qwindows.lib
- ${qt_prefix}/lib/Qt5PlatformSupport.lib
+ ${qt_prefix}/plugins/styles/qwindowsvistastyle.lib
+ ${qt_prefix}/lib/Qt5EventDispatcherSupport.lib
+ ${qt_prefix}/lib/Qt5FontDatabaseSupport.lib
+ ${qt_prefix}/lib/Qt5ThemeSupport.lib
${qt_prefix}/lib/qtfreetype.lib
+ ${qt_prefix}/lib/qtlibpng.lib
imm32.lib
+ wtsapi32.lib
)
set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
CMAKE_DOC_DIR:STRING=doc/cmake
@@ -31,7 +36,7 @@ CMAKE_PREFIX_PATH:STRING=${qt_prefix}
CMake_TEST_Qt4:BOOL=OFF
CMake_TEST_Qt5:BOOL=OFF
")
-set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000 -D_USING_V110_SDK71_")
+set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000")
set(CFLAGS "${ppflags}")
set(CXXFLAGS "${ppflags}")
set(ENV ". ~/rel/env32")
@@ -40,5 +45,9 @@ set(GIT_EXTRA "git config core.autocrlf true")
if(CMAKE_CREATE_VERSION STREQUAL "nightly")
# Some tests fail spuriously too often.
set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'")
+ set(SIGN "")
+else()
+ string(APPEND INITIAL_CACHE "CMake_INSTALL_SIGNTOOL:STRING=signtool\n")
+ set(SIGN [[signtool sign -v -a -tr http://timestamp.digicert.com -fd sha256 -td sha256 -d "CMake Windows Installer" cmake-*.msi]])
endif()
include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake
index 84172067d..5a93ce6b3 100644
--- a/Utilities/Release/win64_release.cmake
+++ b/Utilities/Release/win64_release.cmake
@@ -8,12 +8,17 @@ set(CPACK_BINARY_GENERATORS "WIX ZIP")
set(CPACK_SOURCE_GENERATORS "")
set(MAKE_PROGRAM "ninja")
set(MAKE "${MAKE_PROGRAM} -j16")
-set(qt_prefix "c:/Qt/5.6.3/msvc2017-64-xp-mt")
+set(qt_prefix "c:/Qt/5.12.1/msvc2017-64-w7-mt")
set(qt_win_libs
${qt_prefix}/plugins/platforms/qwindows.lib
- ${qt_prefix}/lib/Qt5PlatformSupport.lib
+ ${qt_prefix}/plugins/styles/qwindowsvistastyle.lib
+ ${qt_prefix}/lib/Qt5EventDispatcherSupport.lib
+ ${qt_prefix}/lib/Qt5FontDatabaseSupport.lib
+ ${qt_prefix}/lib/Qt5ThemeSupport.lib
${qt_prefix}/lib/qtfreetype.lib
+ ${qt_prefix}/lib/qtlibpng.lib
imm32.lib
+ wtsapi32.lib
)
set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
CMAKE_DOC_DIR:STRING=doc/cmake
@@ -31,7 +36,7 @@ CMAKE_PREFIX_PATH:STRING=${qt_prefix}
CMake_TEST_Qt4:BOOL=OFF
CMake_TEST_Qt5:BOOL=OFF
")
-set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000 -D_USING_V110_SDK71_")
+set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000")
set(CFLAGS "${ppflags}")
set(CXXFLAGS "${ppflags}")
set(ENV ". ~/rel/env64")
@@ -40,5 +45,9 @@ set(GIT_EXTRA "git config core.autocrlf true")
if(CMAKE_CREATE_VERSION STREQUAL "nightly")
# Some tests fail spuriously too often.
set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'")
+ set(SIGN "")
+else()
+ string(APPEND INITIAL_CACHE "CMake_INSTALL_SIGNTOOL:STRING=signtool\n")
+ set(SIGN [[signtool sign -v -a -tr http://timestamp.digicert.com -fd sha256 -td sha256 -d "CMake Windows Installer" cmake-*.msi]])
endif()
include(${path}/release_cmake.cmake)
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index fb46052e8..5c2a331c0 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -8,7 +8,7 @@ readonly name="curl"
readonly ownership="Curl Upstream <curl-library@cool.haxx.se>"
readonly subtree="Utilities/cmcurl"
readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_62_0"
+readonly tag="curl-7_65_0"
readonly shortlog=false
readonly paths="
CMake/*
diff --git a/Utilities/Scripts/update-expat.bash b/Utilities/Scripts/update-expat.bash
index 4ac5ef32c..0b52ddc67 100755
--- a/Utilities/Scripts/update-expat.bash
+++ b/Utilities/Scripts/update-expat.bash
@@ -8,7 +8,7 @@ readonly name="expat"
readonly ownership="Expat Upstream <kwrobot@kitware.com>"
readonly subtree="Utilities/cmexpat"
readonly repo="https://github.com/libexpat/libexpat.git"
-readonly tag="R_2_2_3"
+readonly tag="R_2_2_7"
readonly shortlog=false
readonly paths="
expat/lib/asciitab.h
diff --git a/Utilities/Scripts/update-third-party.bash b/Utilities/Scripts/update-third-party.bash
index 670946ef4..fcab871bd 100644
--- a/Utilities/Scripts/update-third-party.bash
+++ b/Utilities/Scripts/update-third-party.bash
@@ -71,8 +71,6 @@ warn () {
readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
-readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
-readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
########################################################################
# Sanity checking
@@ -87,6 +85,18 @@ readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$ba
die "'repo' is empty"
[ -n "$tag" ] || \
die "'tag' is empty"
+
+# Check for an empty destination directory on disk. By checking on disk and
+# not in the repo it allows a library to be freshly re-inialized in a single
+# commit rather than first deleting the old copy in one commit and adding the
+# new copy in a seperate commit.
+if [ ! -d "$(git rev-parse --show-toplevel)/$subtree" ]; then
+ readonly basehash=""
+else
+ readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
+fi
+readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
+
[ -n "$basehash" ] || \
warn "'basehash' is empty; performing initial import"
readonly do_shortlog="${shortlog-false}"
@@ -104,6 +114,8 @@ trap "rm -rf '$workdir'" EXIT
git clone "$repo" "$upstreamdir"
if [ -n "$basehash" ]; then
+ # Remove old worktrees
+ git worktree prune
# Use the existing package's history
git worktree add "$extractdir" "$basehash"
# Clear out the working tree
@@ -163,13 +175,17 @@ popd
if [ -n "$basehash" ]; then
git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name"
else
+ # Note: on Windows 'git merge --help' will open a browser, and the check
+ # will fail, so use the flag by default.
unrelated_histories_flag=""
- if git merge --help | grep -q -e allow-unrelated-histories; then
+ if git --version | grep -q windows; then
+ unrelated_histories_flag="--allow-unrelated-histories "
+ elif git merge --help | grep -q -e allow-unrelated-histories; then
unrelated_histories_flag="--allow-unrelated-histories "
fi
readonly unrelated_histories_flag
- git fetch "$extractdir" "upstream-$name:upstream-$name"
+ git fetch "$extractdir" "+upstream-$name:upstream-$name"
git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name"
git read-tree -u --prefix="$subtree/" "upstream-$name"
fi
diff --git a/Utilities/Scripts/update-zstd.bash b/Utilities/Scripts/update-zstd.bash
new file mode 100755
index 000000000..ce2c66b64
--- /dev/null
+++ b/Utilities/Scripts/update-zstd.bash
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="zstd"
+readonly ownership="zstd upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmzstd"
+readonly repo="https://github.com/facebook/zstd.git"
+readonly tag="v1.3.8"
+readonly shortlog=false
+readonly paths="
+ LICENSE
+ README.md
+ lib/common/*.c
+ lib/common/*.h
+ lib/compress/*.c
+ lib/compress/*.h
+ lib/decompress/*.c
+ lib/decompress/*.h
+ lib/deprecated/*.c
+ lib/deprecated/*.h
+ lib/dictBuilder/*.c
+ lib/dictBuilder/*.h
+ lib/zstd.h
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ echo "* -whitespace" > .gitattributes
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index 15204d63f..c5b2bfe2e 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeHelp_STANDALONE 1)
- cmake_minimum_required(VERSION 3.1...3.12 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.1...3.14 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)
diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in
index 46e0490c0..1456e34c7 100644
--- a/Utilities/cmThirdParty.h.in
+++ b/Utilities/cmThirdParty.h.in
@@ -15,5 +15,6 @@
#cmakedefine CMAKE_USE_SYSTEM_JSONCPP
#cmakedefine CMAKE_USE_SYSTEM_LIBRHASH
#cmakedefine CMAKE_USE_SYSTEM_LIBUV
+#cmakedefine CMAKE_USE_SYSTEM_ZSTD
#endif
diff --git a/Utilities/cm_zstd.h b/Utilities/cm_zstd.h
new file mode 100644
index 000000000..4bda996aa
--- /dev/null
+++ b/Utilities/cm_zstd.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_zstd_h
+#define cm_zstd_h
+
+/* Use the libzstd configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_ZSTD
+# include <zstd.h>
+#else
+# include <cmzstd/lib/zstd.h>
+#endif
+
+#endif
diff --git a/Utilities/cmcompress/CMakeLists.txt b/Utilities/cmcompress/CMakeLists.txt
deleted file mode 100644
index 806357327..000000000
--- a/Utilities/cmcompress/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-PROJECT(CMCompress)
-
-ADD_LIBRARY(cmcompress cmcompress.c)
-
-INSTALL(FILES Copyright.txt DESTINATION ${CMAKE_DOC_DIR}/cmcompress)
diff --git a/Utilities/cmcompress/Copyright.txt b/Utilities/cmcompress/Copyright.txt
deleted file mode 100644
index 162332f69..000000000
--- a/Utilities/cmcompress/Copyright.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-Copyright (c) 1985, 1986 The Regents of the University of California.
-All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-James A. Woods, derived from original work by Spencer Thomas
-and Joseph Orost.
-
-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. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by the University of
- California, Berkeley and its contributors.
-4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
diff --git a/Utilities/cmcompress/cmcompress.c b/Utilities/cmcompress/cmcompress.c
deleted file mode 100644
index ea845ed5f..000000000
--- a/Utilities/cmcompress/cmcompress.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 "cmcompress.h"
-
-#include <errno.h>
-#include <string.h>
-
-static const char_type magic_header[] = { "\037\235" }; /* 1F 9D */
-
-/* Defines for third byte of header */
-#define BIT_MASK 0x1f
-#define BLOCK_MASK 0x80
-#define CHECK_GAP 10000 /* ratio check interval */
-/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
- a fourth header byte (for expansion).
- */
-#define INIT_BITS 9 /* initial number of bits/code */
-
-#ifdef COMPATIBLE /* But wrong! */
-# define MAXCODE(n_bits) (1 << (n_bits) - 1)
-#else
-# define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
-#endif /* COMPATIBLE */
-
-#define htabof(i) cdata->htab[i]
-#define codetabof(i) cdata->codetab[i]
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define FIRST 257 /* first free entry */
-#define CLEAR 256 /* table clear output code */
-
-#ifdef DEBUG
-static void prratio( FILE *stream, long int num, long int den);
-#endif
-
-int cmcompress_compress_initialize(struct cmcompress_stream* cdata)
-{
- cdata->maxbits = BITS; /* user settable max # bits/code */
- cdata->maxmaxcode = 1 << BITS; /* should NEVER generate this code */
- cdata->hsize = HSIZE; /* for dynamic table sizing */
- cdata->free_ent = 0; /* first unused entry */
- cdata->nomagic = 0; /* Use a 3-byte magic number header, unless old file */
- cdata->block_compress = BLOCK_MASK;
- cdata->clear_flg = 0;
- cdata->ratio = 0;
- cdata->checkpoint = CHECK_GAP;
-
- cdata->input_stream = 0;
- cdata->output_stream = 0;
- cdata->client_data = 0;
- return 1;
-}
-
-static void cl_hash(struct cmcompress_stream* cdata, count_int hsize) /* reset code table */
-{
- register count_int *htab_p = cdata->htab+hsize;
- register long i;
- register long m1 = -1;
-
- i = hsize - 16;
- do
- { /* might use Sys V memset(3) here */
- *(htab_p-16) = m1;
- *(htab_p-15) = m1;
- *(htab_p-14) = m1;
- *(htab_p-13) = m1;
- *(htab_p-12) = m1;
- *(htab_p-11) = m1;
- *(htab_p-10) = m1;
- *(htab_p-9) = m1;
- *(htab_p-8) = m1;
- *(htab_p-7) = m1;
- *(htab_p-6) = m1;
- *(htab_p-5) = m1;
- *(htab_p-4) = m1;
- *(htab_p-3) = m1;
- *(htab_p-2) = m1;
- *(htab_p-1) = m1;
- htab_p -= 16;
- }
- while ((i -= 16) >= 0);
- for ( i += 16; i > 0; i-- )
- {
- *--htab_p = m1;
- }
-}
-
-/*-
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits =< (long)wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
-static char buf[BITS];
-
-#ifndef vax
-char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
-char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-#endif /* vax */
-
-static int output(struct cmcompress_stream* cdata, code_int code)
-{
-#ifdef DEBUG
- static int col = 0;
-#endif /* DEBUG */
-
- /*
- * On the VAX, it is important to have the register declarations
- * in exactly the order given, or the asm will break.
- */
- register int r_off = cdata->offset, bits= cdata->n_bits;
- register char * bp = buf;
-
-#ifdef DEBUG
- if ( verbose )
- {
- fprintf( stderr, "%5d%c", code,
- (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
- }
-#endif /* DEBUG */
- if ( code >= 0 )
- {
-#if defined(vax) && !defined(__GNUC__)
- /*
- * VAX and PCC DEPENDENT!! Implementation on other machines is
- * below.
- *
- * Translation: Insert BITS bits from the argument starting at
- * cdata->offset bits from the beginning of buf.
- */
- 0; /* Work around for pcc -O bug with asm and if stmt */
- asm( "insv 4(ap),r11,r10,(r9)" );
-#else
- /*
- * byte/bit numbering on the VAX is simulated by the following code
- */
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
- /*
- * Since code is always >= 8 bits, only need to mask the first
- * hunk on the left.
- */
- *bp = (char)((*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]));
- bp++;
- bits -= (8 - r_off);
- code >>= 8 - r_off;
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 )
- {
- *bp++ = (char)(code);
- code >>= 8;
- bits -= 8;
- }
- /* Last bits. */
- if(bits)
- {
- *bp = (char)(code);
- }
-#endif /* vax */
- cdata->offset += cdata->n_bits;
- if ( cdata->offset == (cdata->n_bits << 3) )
- {
- bp = buf;
- bits = cdata->n_bits;
- cdata->bytes_out += bits;
- do
- {
- if ( cdata->output_stream(cdata, bp, 1) != 1 )
- {
- return 0;
- }
- bp++;
- }
- while(--bits);
- cdata->offset = 0;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
- if ( cdata->free_ent > cdata->maxcode || (cdata->clear_flg > 0))
- {
- /*
- * Write the whole buffer, because the input side won't
- * discover the size increase until after it has read it.
- */
- if ( cdata->offset > 0 )
- {
- if ( cdata->output_stream(cdata, buf, cdata->n_bits) != cdata->n_bits )
- {
- return 0;
- }
- cdata->bytes_out += cdata->n_bits;
- }
- cdata->offset = 0;
-
- if ( cdata->clear_flg )
- {
- cdata->maxcode = MAXCODE (cdata->n_bits = INIT_BITS);
- cdata->clear_flg = 0;
- }
- else
- {
- cdata->n_bits++;
- if ( cdata->n_bits == cdata->maxbits )
- {
- cdata->maxcode = cdata->maxmaxcode;
- }
- else
- {
- cdata->maxcode = MAXCODE(cdata->n_bits);
- }
- }
-#ifdef DEBUG
- if ( debug )
- {
- fprintf( stderr, "\nChange to %d bits\n", cdata->n_bits );
- col = 0;
- }
-#endif /* DEBUG */
- }
- }
- else
- {
- /*
- * At EOF, write the rest of the buffer.
- */
- if ( cdata->offset > 0 )
- {
- cdata->offset = (cdata->offset + 7) / 8;
- if ( cdata->output_stream(cdata, buf, cdata->offset ) != cdata->offset )
- {
- return 0;
- }
- cdata->bytes_out += cdata->offset;
- }
- cdata->offset = 0;
- (void)fflush( stdout );
- if( ferror( stdout ) )
- {
- return 0;
- }
-#ifdef DEBUG
- if ( verbose )
- {
- fprintf( stderr, "\n" );
- }
-#endif
- }
- return 1;
-}
-
-/*
- * compress stdin to stdout
- *
- * Algorithm: use open addressing double hashing (no chaining) on the
- * prefix code / next character combination. We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe. Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation. Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills. The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor. Late addition: construct the table according to
- * file size for noticeable speed improvement on small files. Please direct
- * questions about this implementation to ames!jaw.
- */
-
-int cmcompress_compress_start(struct cmcompress_stream* cdata)
-{
-#ifndef COMPATIBLE
- if (cdata->nomagic == 0)
- {
- char headLast = (char)(cdata->maxbits | cdata->block_compress);
- cdata->output_stream(cdata, (const char*)magic_header, 2);
- cdata->output_stream(cdata, &headLast, 1);
- if(ferror(stdout))
- {
- printf("Error...\n");
- }
- }
-#endif /* COMPATIBLE */
-
- cdata->offset = 0;
- cdata->bytes_out = 3; /* includes 3-byte header mojo */
- cdata->out_count = 0;
- cdata->clear_flg = 0;
- cdata->ratio = 0;
- cdata->in_count = 1;
- cdata->checkpoint = CHECK_GAP;
- cdata->maxcode = MAXCODE(cdata->n_bits = INIT_BITS);
- cdata->free_ent = ((cdata->block_compress) ? FIRST : 256 );
-
- cdata->first_pass = 1;
-
- cdata->hshift = 0;
- for ( cdata->fcode = (long) cdata->hsize; cdata->fcode < 65536L; cdata->fcode *= 2L )
- {
- cdata->hshift++;
- }
- cdata->hshift = 8 - cdata->hshift; /* set hash code range bound */
-
- cdata->hsize_reg = cdata->hsize;
- cl_hash(cdata, (count_int) cdata->hsize_reg); /* clear hash table */
-
- return 1;
-}
-
-static int cl_block (struct cmcompress_stream* cdata) /* table clear for block compress */
-{
- register long int rat;
-
- cdata->checkpoint = cdata->in_count + CHECK_GAP;
-#ifdef DEBUG
- if ( cdata->debug )
- {
- fprintf ( stderr, "count: %ld, ratio: ", cdata->in_count );
- prratio ( stderr, cdata->in_count, cdata->bytes_out );
- fprintf ( stderr, "\n");
- }
-#endif /* DEBUG */
-
- if(cdata->in_count > 0x007fffff)
- { /* shift will overflow */
- rat = cdata->bytes_out >> 8;
- if(rat == 0)
- { /* Don't divide by zero */
- rat = 0x7fffffff;
- }
- else
- {
- rat = cdata->in_count / rat;
- }
- }
- else
- {
- rat = (cdata->in_count << 8) / cdata->bytes_out; /* 8 fractional bits */
- }
- if ( rat > cdata->ratio )
- {
- cdata->ratio = rat;
- }
- else
- {
- cdata->ratio = 0;
-#ifdef DEBUG
- if(cdata->verbose)
- {
- dump_tab(); /* dump string table */
- }
-#endif
- cl_hash (cdata, (count_int) cdata->hsize );
- cdata->free_ent = FIRST;
- cdata->clear_flg = 1;
- if ( !output (cdata, (code_int) CLEAR ) )
- {
- return 0;
- }
-#ifdef DEBUG
- if(cdata->debug)
- {
- fprintf ( stderr, "clear\n" );
- }
-#endif /* DEBUG */
- }
- return 1;
-}
-
-
-int cmcompress_compress(struct cmcompress_stream* cdata, void* buff, size_t n)
-{
- register code_int i;
- register int c;
- register int disp;
-
- unsigned char* input_buffer = (unsigned char*)buff;
-
- size_t cc;
-
- /*printf("cmcompress_compress(%p, %p, %d)\n", cdata, buff, n);*/
-
- if ( cdata->first_pass )
- {
- cdata->ent = input_buffer[0];
- ++ input_buffer;
- -- n;
- cdata->first_pass = 0;
- }
-
- for ( cc = 0; cc < n; ++ cc )
- {
- c = input_buffer[cc];
- cdata->in_count++;
- cdata->fcode = (long) (((long) c << cdata->maxbits) + cdata->ent);
- i = ((c << cdata->hshift) ^ cdata->ent); /* xor hashing */
-
- if ( htabof (i) == cdata->fcode )
- {
- cdata->ent = codetabof (i);
- continue;
- }
- else if ( (long)htabof (i) < 0 ) /* empty slot */
- {
- goto nomatch;
- }
- disp = (int)(cdata->hsize_reg - i); /* secondary hash (after G. Knott) */
- if ( i == 0 )
- {
- disp = 1;
- }
-probe:
- if ( (i -= disp) < 0 )
- {
- i += cdata->hsize_reg;
- }
-
- if ( htabof (i) == cdata->fcode )
- {
- cdata->ent = codetabof (i);
- continue;
- }
- if ( (long)htabof (i) > 0 )
- {
- goto probe;
- }
-nomatch:
- if ( !output(cdata, (code_int) cdata->ent ) )
- {
- return 0;
- }
- cdata->out_count++;
- cdata->ent = c;
- if (
-#ifdef SIGNED_COMPARE_SLOW
- (unsigned) cdata->free_ent < (unsigned) cdata->maxmaxcode
-#else
- cdata->free_ent < cdata->maxmaxcode
-#endif
- )
- {
- codetabof (i) = (unsigned short)(cdata->free_ent++); /* code -> hashtable */
- htabof (i) = cdata->fcode;
- }
- else if ( (count_int)cdata->in_count >= cdata->checkpoint && cdata->block_compress )
- {
- if ( !cl_block (cdata) )
- {
- return 0;
- }
- }
- }
-
- return 1;
-}
-
-int cmcompress_compress_finalize(struct cmcompress_stream* cdata)
-{
- /*
- * Put out the final code.
- */
- if ( !output(cdata, (code_int)cdata->ent ) )
- {
- return 0;
- }
- cdata->out_count++;
- if ( !output(cdata, (code_int)-1 ) )
- {
- return 0;
- }
-
- if(cdata->bytes_out > cdata->in_count) /* exit(2) if no savings */
- {
- return 0;
- }
- return 1;
-}
-
-
-#if defined(DEBUG)
-static void prratio(FILE *stream, long int num, long int den)
-{
- register int q; /* Doesn't need to be long */
-
- if(num > 214748L)
- { /* 2147483647/10000 */
- q = num / (den / 10000L);
- }
- else
- {
- q = 10000L * num / den; /* Long calculations, though */
- }
- if (q < 0)
- {
- putc('-', stream);
- q = -q;
- }
- fprintf(stream, "%d.%02d%%", q / 100, q % 100);
-}
-#endif
-
diff --git a/Utilities/cmcompress/cmcompress.h b/Utilities/cmcompress/cmcompress.h
deleted file mode 100644
index 4cd3a1c3e..000000000
--- a/Utilities/cmcompress/cmcompress.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- */
-
-#ifndef cmcompress__h_
-#define cmcompress__h_
-
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /*
- * Set USERMEM to the maximum amount of physical user memory available
- * in bytes. USERMEM is used to determine the maximum BITS that can be used
- * for compression.
- *
- * SACREDMEM is the amount of physical memory saved for others; compress
- * will hog the rest.
- */
-#ifndef SACREDMEM
-#define SACREDMEM 0
-#endif
-
-#ifndef USERMEM
-# define USERMEM 450000 /* default user memory */
-#endif
-
-#ifdef pdp11
-# define BITS 12 /* max bits/code for 16-bit machine */
-# define NO_UCHAR /* also if "unsigned char" functions as signed char */
-# undef USERMEM
-#endif /* pdp11 */ /* don't forget to compile with -i */
-
-#ifdef USERMEM
-# if USERMEM >= (433484+SACREDMEM)
-# define PBITS 16
-# else
-# if USERMEM >= (229600+SACREDMEM)
-# define PBITS 15
-# else
-# if USERMEM >= (127536+SACREDMEM)
-# define PBITS 14
-# else
-# if USERMEM >= (73464+SACREDMEM)
-# define PBITS 13
-# else
-# define PBITS 12
-# endif
-# endif
-# endif
-# endif
-# undef USERMEM
-#endif /* USERMEM */
-
-#ifdef PBITS /* Preferred BITS for this memory size */
-# ifndef BITS
-# define BITS PBITS
-# endif /* BITS */
-#endif /* PBITS */
-
-#if BITS == 16
-# define HSIZE 69001 /* 95% occupancy */
-#endif
-#if BITS == 15
-# define HSIZE 35023 /* 94% occupancy */
-#endif
-#if BITS == 14
-# define HSIZE 18013 /* 91% occupancy */
-#endif
-#if BITS == 13
-# define HSIZE 9001 /* 91% occupancy */
-#endif
-#if BITS <= 12
-# define HSIZE 5003 /* 80% occupancy */
-#endif
-
- /*
- * a code_int must be able to hold 2**BITS values of type int, and also -1
- */
-#if BITS > 15
- typedef long int code_int;
-#else
- typedef int code_int;
-#endif
-
-#ifdef SIGNED_COMPARE_SLOW
- typedef unsigned long int count_int;
- typedef unsigned short int count_short;
-#else
- typedef long int count_int;
-#endif
-
-#ifdef NO_UCHAR
- typedef char char_type;
-#else
- typedef unsigned char char_type;
-#endif /* UCHAR */
-
-
-
- struct cmcompress_stream
- {
- int n_bits; /* number of bits/code */
- int maxbits; /* user settable max # bits/code */
- code_int maxcode; /* maximum code, given n_bits */
- code_int maxmaxcode; /* should NEVER generate this code */
-
- count_int htab [HSIZE];
- unsigned short codetab [HSIZE];
-
- code_int hsize; /* for dynamic table sizing */
- code_int free_ent; /* first unused entry */
- int nomagic; /* Use a 3-byte magic number header, unless old file */
-
- /*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
- int block_compress;
- int clear_flg;
- long int ratio;
- count_int checkpoint;
-
-#ifdef DEBUG
- int debug;
- int verbose;
-#endif
-
- /* compress internals */
- int offset;
- long int in_count; /* length of input */
- long int bytes_out; /* length of compressed output */
- long int out_count; /* # of codes output (for debugging) */
-
- /* internals */
- code_int ent;
- code_int hsize_reg;
- int hshift;
-
- long fcode;
- int first_pass;
-
- /* For input and output */
- int (*input_stream)(void*);
- int (*output_stream)(void*, const char*,int);
- void* client_data;
- };
-
- int cmcompress_compress_initialize(struct cmcompress_stream* cdata);
- int cmcompress_compress_start(struct cmcompress_stream* cdata);
- int cmcompress_compress(struct cmcompress_stream* cdata, void* buff, size_t n);
- int cmcompress_compress_finalize(struct cmcompress_stream* cdata);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* cmcompress__h_ */
diff --git a/Utilities/cmcompress/compress.c.original b/Utilities/cmcompress/compress.c.original
deleted file mode 100644
index 5062bda98..000000000
--- a/Utilities/cmcompress/compress.c.original
+++ /dev/null
@@ -1,1308 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- */
-
-#ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1985, 1986 The Regents of the University of California.\n\
- All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)compress.c 5.19 (Berkeley) 3/18/91";
-#endif /* not lint */
-
-/*
- * compress.c - File compression ala IEEE Computer, June 1984.
- *
- * Authors: Spencer W. Thomas (decvax!utah-cs!thomas)
- * Jim McKie (decvax!mcvax!jim)
- * Steve Davies (decvax!vax135!petsd!peora!srd)
- * Ken Turkowski (decvax!decwrl!turtlevax!ken)
- * James A. Woods (decvax!ihnp4!ames!jaw)
- * Joe Orost (decvax!vax135!petsd!joe)
- */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <utime.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Set USERMEM to the maximum amount of physical user memory available
- * in bytes. USERMEM is used to determine the maximum BITS that can be used
- * for compression.
- *
- * SACREDMEM is the amount of physical memory saved for others; compress
- * will hog the rest.
- */
-#ifndef SACREDMEM
-#define SACREDMEM 0
-#endif
-
-#ifndef USERMEM
-# define USERMEM 450000 /* default user memory */
-#endif
-
-#ifdef pdp11
-# define BITS 12 /* max bits/code for 16-bit machine */
-# define NO_UCHAR /* also if "unsigned char" functions as signed char */
-# undef USERMEM
-#endif /* pdp11 */ /* don't forget to compile with -i */
-
-#ifdef USERMEM
-# if USERMEM >= (433484+SACREDMEM)
-# define PBITS 16
-# else
-# if USERMEM >= (229600+SACREDMEM)
-# define PBITS 15
-# else
-# if USERMEM >= (127536+SACREDMEM)
-# define PBITS 14
-# else
-# if USERMEM >= (73464+SACREDMEM)
-# define PBITS 13
-# else
-# define PBITS 12
-# endif
-# endif
-# endif
-# endif
-# undef USERMEM
-#endif /* USERMEM */
-
-#ifdef PBITS /* Preferred BITS for this memory size */
-# ifndef BITS
-# define BITS PBITS
-# endif BITS
-#endif /* PBITS */
-
-#if BITS == 16
-# define HSIZE 69001 /* 95% occupancy */
-#endif
-#if BITS == 15
-# define HSIZE 35023 /* 94% occupancy */
-#endif
-#if BITS == 14
-# define HSIZE 18013 /* 91% occupancy */
-#endif
-#if BITS == 13
-# define HSIZE 9001 /* 91% occupancy */
-#endif
-#if BITS <= 12
-# define HSIZE 5003 /* 80% occupancy */
-#endif
-
-/*
- * a code_int must be able to hold 2**BITS values of type int, and also -1
- */
-#if BITS > 15
-typedef long int code_int;
-#else
-typedef int code_int;
-#endif
-
-#ifdef SIGNED_COMPARE_SLOW
-typedef unsigned long int count_int;
-typedef unsigned short int count_short;
-#else
-typedef long int count_int;
-#endif
-
-#ifdef NO_UCHAR
- typedef char char_type;
-#else
- typedef unsigned char char_type;
-#endif /* UCHAR */
-char_type magic_header[] = { "\037\235" }; /* 1F 9D */
-
-/* Defines for third byte of header */
-#define BIT_MASK 0x1f
-#define BLOCK_MASK 0x80
-/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
- a fourth header byte (for expansion).
-*/
-#define INIT_BITS 9 /* initial number of bits/code */
-
-int n_bits; /* number of bits/code */
-int maxbits = BITS; /* user settable max # bits/code */
-code_int maxcode; /* maximum code, given n_bits */
-code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
-#ifdef COMPATIBLE /* But wrong! */
-# define MAXCODE(n_bits) (1 << (n_bits) - 1)
-#else
-# define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
-#endif /* COMPATIBLE */
-
-count_int htab [HSIZE];
-unsigned short codetab [HSIZE];
-
-#define htabof(i) htab[i]
-#define codetabof(i) codetab[i]
-code_int hsize = HSIZE; /* for dynamic table sizing */
-count_int fsize;
-
-/*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress(). The tab_prefix table is the same size and type
- * as the codetab. The tab_suffix table needs 2**BITS characters. We
- * get this from the beginning of htab. The output stack uses the rest
- * of htab, and contains characters. There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
-#define tab_prefixof(i) codetabof(i)
-# define tab_suffixof(i) ((char_type *)(htab))[i]
-# define de_stack ((char_type *)&tab_suffixof(1<<BITS))
-
-code_int free_ent = 0; /* first unused entry */
-int exit_stat = 0; /* per-file status */
-int perm_stat = 0; /* permanent status */
-
-code_int getcode();
-
-int nomagic = 0; /* Use a 3-byte magic number header, unless old file */
-int zcat_flg = 0; /* Write output on stdout, suppress messages */
-int precious = 1; /* Don't unlink output file on interrupt */
-int quiet = 1; /* don't tell me about compression */
-
-/*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
-int block_compress = BLOCK_MASK;
-int clear_flg = 0;
-long int ratio = 0;
-#define CHECK_GAP 10000 /* ratio check interval */
-count_int checkpoint = CHECK_GAP;
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define FIRST 257 /* first free entry */
-#define CLEAR 256 /* table clear output code */
-
-int force = 0;
-char ofname [100];
-#ifdef DEBUG
-int debug, verbose;
-#endif
-sig_t oldint;
-int bgnd_flag;
-
-int do_decomp = 0;
-
-/*-
- * Algorithm from "A Technique for High Performance Data Compression",
- * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
- *
- * Usage: compress [-dfvc] [-b bits] [file ...]
- * Inputs:
- * -d: If given, decompression is done instead.
- *
- * -c: Write output on stdout, don't remove original.
- *
- * -b: Parameter limits the max number of bits/code.
- *
- * -f: Forces output file to be generated, even if one already
- * exists, and even if no space is saved by compressing.
- * If -f is not used, the user will be prompted if stdin is
- * a tty, otherwise, the output file will not be overwritten.
- *
- * -v: Write compression statistics
- *
- * file ...: Files to be compressed. If none specified, stdin
- * is used.
- * Outputs:
- * file.Z: Compressed form of file with same mode, owner, and utimes
- * or stdout (if stdin used as input)
- *
- * Assumptions:
- * When filenames are given, replaces with the compressed version
- * (.Z suffix) only if the file decreases in size.
- * Algorithm:
- * Modified Lempel-Ziv method (LZW). Basically finds common
- * substrings and replaces them with a variable size code. This is
- * deterministic, and can be done on the fly. Thus, the decompression
- * procedure needs no input table, but tracks the way the table was built.
- */
-
-main(argc, argv)
- int argc;
- char **argv;
-{
- extern int optind;
- extern char *optarg;
- struct stat statbuf;
- int ch, overwrite;
- char **filelist, **fileptr, *cp, tempname[MAXPATHLEN];
- void onintr(), oops();
-
- /* This bg check only works for sh. */
- if ((oldint = signal(SIGINT, SIG_IGN)) != SIG_IGN) {
- (void)signal(SIGINT, onintr);
- (void)signal(SIGSEGV, oops); /* XXX */
- }
- bgnd_flag = oldint != SIG_DFL;
-
-#ifdef COMPATIBLE
- nomagic = 1; /* Original didn't have a magic number */
-#endif
-
- if (cp = rindex(argv[0], '/'))
- ++cp;
- else
- cp = argv[0];
- if (strcmp(cp, "uncompress") == 0)
- do_decomp = 1;
- else if(strcmp(cp, "zcat") == 0) {
- do_decomp = 1;
- zcat_flg = 1;
- }
-
- /*
- * -b maxbits => maxbits.
- * -C => generate output compatible with compress 2.0.
- * -c => cat all output to stdout
- * -D => debug
- * -d => do_decomp
- * -f => force overwrite of output file
- * -n => no header: useful to uncompress old files
- * -V => print Version; debug verbose
- * -v => unquiet
- */
-
- overwrite = 0;
-#ifdef DEBUG
- while ((ch = getopt(argc, argv, "b:CcDdfnVv")) != EOF)
-#else
- while ((ch = getopt(argc, argv, "b:Ccdfnv")) != EOF)
-#endif
- switch(ch) {
- case 'b':
- maxbits = atoi(optarg);
- break;
- case 'C':
- block_compress = 0;
- break;
- case 'c':
- zcat_flg = 1;
- break;
-#ifdef DEBUG
- case 'D':
- debug = 1;
- break;
-#endif
- case 'd':
- do_decomp = 1;
- break;
- case 'f':
- overwrite = 1;
- force = 1;
- break;
- case 'n':
- nomagic = 1;
- break;
- case 'q':
- quiet = 1;
- break;
-#ifdef DEBUG
- case 'V':
- verbose = 1;
- break;
-#endif
- case 'v':
- quiet = 0;
- break;
- case '?':
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (maxbits < INIT_BITS)
- maxbits = INIT_BITS;
- if (maxbits > BITS)
- maxbits = BITS;
- maxmaxcode = 1 << maxbits;
-
- /* Build useless input file list. */
- filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
- while (*argv)
- *fileptr++ = *argv++;
- *fileptr = NULL;
-
- if (*filelist != NULL) {
- for (fileptr = filelist; *fileptr; fileptr++) {
- exit_stat = 0;
- if (do_decomp) { /* DECOMPRESSION */
- /* Check for .Z suffix */
- if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
- /* No .Z: tack one on */
- strcpy(tempname, *fileptr);
- strcat(tempname, ".Z");
- *fileptr = tempname;
- }
- /* Open input file */
- if ((freopen(*fileptr, "r", stdin)) == NULL) {
- perror(*fileptr);
- perm_stat = 1;
- continue;
- }
- /* Check the magic number */
- if (nomagic == 0) {
- if ((getchar() != (magic_header[0] & 0xFF))
- || (getchar() != (magic_header[1] & 0xFF))) {
- fprintf(stderr, "%s: not in compressed format\n",
- *fileptr);
- continue;
- }
- maxbits = getchar(); /* set -b from file */
- block_compress = maxbits & BLOCK_MASK;
- maxbits &= BIT_MASK;
- maxmaxcode = 1 << maxbits;
- if(maxbits > BITS) {
- fprintf(stderr,
- "%s: compressed with %d bits, can only handle %d bits\n",
- *fileptr, maxbits, BITS);
- continue;
- }
- }
- /* Generate output filename */
- strcpy(ofname, *fileptr);
- ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
- } else { /* COMPRESSION */
- if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
- fprintf(stderr, "%s: already has .Z suffix -- no change\n",
- *fileptr);
- continue;
- }
- /* Open input file */
- if ((freopen(*fileptr, "r", stdin)) == NULL) {
- perror(*fileptr);
- perm_stat = 1;
- continue;
- }
- stat ( *fileptr, &statbuf );
- fsize = (long) statbuf.st_size;
- /*
- * tune hash table size for small files -- ad hoc,
- * but the sizes match earlier #defines, which
- * serve as upper bounds on the number of output codes.
- */
- hsize = HSIZE;
- if ( fsize < (1 << 12) )
- hsize = MIN ( 5003, HSIZE );
- else if ( fsize < (1 << 13) )
- hsize = MIN ( 9001, HSIZE );
- else if ( fsize < (1 << 14) )
- hsize = MIN ( 18013, HSIZE );
- else if ( fsize < (1 << 15) )
- hsize = MIN ( 35023, HSIZE );
- else if ( fsize < 47000 )
- hsize = MIN ( 50021, HSIZE );
-
- /* Generate output filename */
- strcpy(ofname, *fileptr);
- strcat(ofname, ".Z");
- }
- /* Check for overwrite of existing file */
- if (overwrite == 0 && zcat_flg == 0) {
- if (stat(ofname, &statbuf) == 0) {
- char response[2];
- response[0] = 'n';
- fprintf(stderr, "%s already exists;", ofname);
- if (bgnd_flag == 0 && isatty(2)) {
- fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
- ofname);
- fflush(stderr);
- read(2, response, 2);
- while (response[1] != '\n') {
- if (read(2, response+1, 1) < 0) { /* Ack! */
- perror("stderr"); break;
- }
- }
- }
- if (response[0] != 'y') {
- fprintf(stderr, "\tnot overwritten\n");
- continue;
- }
- }
- }
- if(zcat_flg == 0) { /* Open output file */
- if (freopen(ofname, "w", stdout) == NULL) {
- perror(ofname);
- perm_stat = 1;
- continue;
- }
- precious = 0;
- if(!quiet)
- fprintf(stderr, "%s: ", *fileptr);
- }
-
- /* Actually do the compression/decompression */
- if (do_decomp == 0) compress();
-#ifndef DEBUG
- else decompress();
-#else
- else if (debug == 0) decompress();
- else printcodes();
- if (verbose) dump_tab();
-#endif /* DEBUG */
- if(zcat_flg == 0) {
- copystat(*fileptr, ofname); /* Copy stats */
- precious = 1;
- if((exit_stat == 1) || (!quiet))
- putc('\n', stderr);
- }
- }
- } else { /* Standard input */
- if (do_decomp == 0) {
- compress();
-#ifdef DEBUG
- if(verbose) dump_tab();
-#endif /* DEBUG */
- if(!quiet)
- putc('\n', stderr);
- } else {
- /* Check the magic number */
- if (nomagic == 0) {
- if ((getchar()!=(magic_header[0] & 0xFF))
- || (getchar()!=(magic_header[1] & 0xFF))) {
- fprintf(stderr, "stdin: not in compressed format\n");
- exit(1);
- }
- maxbits = getchar(); /* set -b from file */
- block_compress = maxbits & BLOCK_MASK;
- maxbits &= BIT_MASK;
- maxmaxcode = 1 << maxbits;
- fsize = 100000; /* assume stdin large for USERMEM */
- if(maxbits > BITS) {
- fprintf(stderr,
- "stdin: compressed with %d bits, can only handle %d bits\n",
- maxbits, BITS);
- exit(1);
- }
- }
-#ifndef DEBUG
- decompress();
-#else
- if (debug == 0) decompress();
- else printcodes();
- if (verbose) dump_tab();
-#endif /* DEBUG */
- }
- }
- exit(perm_stat ? perm_stat : exit_stat);
-}
-
-static int offset;
-long int in_count = 1; /* length of input */
-long int bytes_out; /* length of compressed output */
-long int out_count = 0; /* # of codes output (for debugging) */
-
-/*
- * compress stdin to stdout
- *
- * Algorithm: use open addressing double hashing (no chaining) on the
- * prefix code / next character combination. We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe. Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation. Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills. The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor. Late addition: construct the table according to
- * file size for noticeable speed improvement on small files. Please direct
- * questions about this implementation to ames!jaw.
- */
-
-compress()
-{
- register long fcode;
- register code_int i = 0;
- register int c;
- register code_int ent;
- register int disp;
- register code_int hsize_reg;
- register int hshift;
-
-#ifndef COMPATIBLE
- if (nomagic == 0) {
- putchar(magic_header[0]);
- putchar(magic_header[1]);
- putchar((char)(maxbits | block_compress));
- if(ferror(stdout))
- writeerr();
- }
-#endif /* COMPATIBLE */
-
- offset = 0;
- bytes_out = 3; /* includes 3-byte header mojo */
- out_count = 0;
- clear_flg = 0;
- ratio = 0;
- in_count = 1;
- checkpoint = CHECK_GAP;
- maxcode = MAXCODE(n_bits = INIT_BITS);
- free_ent = ((block_compress) ? FIRST : 256 );
-
- ent = getchar ();
-
- hshift = 0;
- for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
- hshift++;
- hshift = 8 - hshift; /* set hash code range bound */
-
- hsize_reg = hsize;
- cl_hash( (count_int) hsize_reg); /* clear hash table */
-
-#ifdef SIGNED_COMPARE_SLOW
- while ( (c = getchar()) != (unsigned) EOF ) {
-#else
- while ( (c = getchar()) != EOF ) {
-#endif
- in_count++;
- fcode = (long) (((long) c << maxbits) + ent);
- i = ((c << hshift) ^ ent); /* xor hashing */
-
- if ( htabof (i) == fcode ) {
- ent = codetabof (i);
- continue;
- } else if ( (long)htabof (i) < 0 ) /* empty slot */
- goto nomatch;
- disp = hsize_reg - i; /* secondary hash (after G. Knott) */
- if ( i == 0 )
- disp = 1;
-probe:
- if ( (i -= disp) < 0 )
- i += hsize_reg;
-
- if ( htabof (i) == fcode ) {
- ent = codetabof (i);
- continue;
- }
- if ( (long)htabof (i) > 0 )
- goto probe;
-nomatch:
- output ( (code_int) ent );
- out_count++;
- ent = c;
-#ifdef SIGNED_COMPARE_SLOW
- if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
-#else
- if ( free_ent < maxmaxcode ) {
-#endif
- codetabof (i) = free_ent++; /* code -> hashtable */
- htabof (i) = fcode;
- }
- else if ( (count_int)in_count >= checkpoint && block_compress )
- cl_block ();
- }
- /*
- * Put out the final code.
- */
- output( (code_int)ent );
- out_count++;
- output( (code_int)-1 );
-
- /*
- * Print out stats on stderr
- */
- if(zcat_flg == 0 && !quiet) {
-#ifdef DEBUG
- fprintf( stderr,
- "%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
- in_count, out_count, bytes_out );
- prratio( stderr, in_count, bytes_out );
- fprintf( stderr, "\n");
- fprintf( stderr, "\tCompression as in compact: " );
- prratio( stderr, in_count-bytes_out, in_count );
- fprintf( stderr, "\n");
- fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
- free_ent - 1, n_bits );
-#else /* !DEBUG */
- fprintf( stderr, "Compression: " );
- prratio( stderr, in_count-bytes_out, in_count );
-#endif /* DEBUG */
- }
- if(bytes_out > in_count) /* exit(2) if no savings */
- exit_stat = 2;
- return;
-}
-
-/*-
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits =< (long)wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
-static char buf[BITS];
-
-#ifndef vax
-char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
-char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-#endif /* vax */
-
-output( code )
-code_int code;
-{
-#ifdef DEBUG
- static int col = 0;
-#endif /* DEBUG */
-
- /*
- * On the VAX, it is important to have the register declarations
- * in exactly the order given, or the asm will break.
- */
- register int r_off = offset, bits= n_bits;
- register char * bp = buf;
-
-#ifdef DEBUG
- if ( verbose )
- fprintf( stderr, "%5d%c", code,
- (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
-#endif /* DEBUG */
- if ( code >= 0 ) {
-#if defined(vax) && !defined(__GNUC__)
- /*
- * VAX and PCC DEPENDENT!! Implementation on other machines is
- * below.
- *
- * Translation: Insert BITS bits from the argument starting at
- * offset bits from the beginning of buf.
- */
- 0; /* Work around for pcc -O bug with asm and if stmt */
- asm( "insv 4(ap),r11,r10,(r9)" );
-#else
-/*
- * byte/bit numbering on the VAX is simulated by the following code
- */
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
- /*
- * Since code is always >= 8 bits, only need to mask the first
- * hunk on the left.
- */
- *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
- bp++;
- bits -= (8 - r_off);
- code >>= 8 - r_off;
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 ) {
- *bp++ = code;
- code >>= 8;
- bits -= 8;
- }
- /* Last bits. */
- if(bits)
- *bp = code;
-#endif /* vax */
- offset += n_bits;
- if ( offset == (n_bits << 3) ) {
- bp = buf;
- bits = n_bits;
- bytes_out += bits;
- do {
- putchar(*bp++);
- if (ferror(stdout))
- writeerr();
- } while(--bits);
- offset = 0;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
- if ( free_ent > maxcode || (clear_flg > 0))
- {
- /*
- * Write the whole buffer, because the input side won't
- * discover the size increase until after it has read it.
- */
- if ( offset > 0 ) {
- if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
- writeerr();
- bytes_out += n_bits;
- }
- offset = 0;
-
- if ( clear_flg ) {
- maxcode = MAXCODE (n_bits = INIT_BITS);
- clear_flg = 0;
- }
- else {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode;
- else
- maxcode = MAXCODE(n_bits);
- }
-#ifdef DEBUG
- if ( debug ) {
- fprintf( stderr, "\nChange to %d bits\n", n_bits );
- col = 0;
- }
-#endif /* DEBUG */
- }
- } else {
- /*
- * At EOF, write the rest of the buffer.
- */
- if ( offset > 0 ) {
- offset = (offset + 7) / 8;
- if( fwrite( buf, 1, offset, stdout ) != offset )
- writeerr();
- bytes_out += offset;
- }
- offset = 0;
- (void)fflush( stdout );
- if( ferror( stdout ) )
- writeerr();
-#ifdef DEBUG
- if ( verbose )
- fprintf( stderr, "\n" );
-#endif
- }
-}
-
-/*
- * Decompress stdin to stdout. This routine adapts to the codes in the
- * file building the "string" table on-the-fly; requiring no table to
- * be stored in the compressed file. The tables used herein are shared
- * with those of the compress() routine. See the definitions above.
- */
-
-decompress() {
- register char_type *stackp;
- register int finchar;
- register code_int code, oldcode, incode;
- int n, nwritten, offset; /* Variables for buffered write */
- char buff[BUFSIZ]; /* Buffer for buffered write */
-
-
- /*
- * As above, initialize the first 256 entries in the table.
- */
- maxcode = MAXCODE(n_bits = INIT_BITS);
- for ( code = 255; code >= 0; code-- ) {
- tab_prefixof(code) = 0;
- tab_suffixof(code) = (char_type)code;
- }
- free_ent = ((block_compress) ? FIRST : 256 );
-
- finchar = oldcode = getcode();
- if(oldcode == -1) /* EOF already? */
- return; /* Get out of here */
-
- /* first code must be 8 bits = char */
- n=0;
- buff[n++] = (char)finchar;
-
- stackp = de_stack;
-
- while ( (code = getcode()) > -1 ) {
-
- if ( (code == CLEAR) && block_compress ) {
- for ( code = 255; code >= 0; code-- )
- tab_prefixof(code) = 0;
- clear_flg = 1;
- free_ent = FIRST - 1;
- if ( (code = getcode ()) == -1 ) /* O, untimely death! */
- break;
- }
- incode = code;
- /*
- * Special case for KwKwK string.
- */
- if ( code >= free_ent ) {
- *stackp++ = finchar;
- code = oldcode;
- }
-
- /*
- * Generate output characters in reverse order
- */
-#ifdef SIGNED_COMPARE_SLOW
- while ( ((unsigned long)code) >= ((unsigned long)256) ) {
-#else
- while ( code >= 256 ) {
-#endif
- *stackp++ = tab_suffixof(code);
- code = tab_prefixof(code);
- }
- *stackp++ = finchar = tab_suffixof(code);
-
- /*
- * And put them out in forward order
- */
- do {
- /*
- * About 60% of the time is spent in the putchar() call
- * that appeared here. It was originally
- * putchar ( *--stackp );
- * If we buffer the writes ourselves, we can go faster (about
- * 30%).
- *
- * At this point, the next line is the next *big* time
- * sink in the code. It takes up about 10% of the time.
- */
- buff[n++] = *--stackp;
- if (n == BUFSIZ) {
- offset = 0;
- do {
- nwritten = write(fileno(stdout), &buff[offset], n);
- if (nwritten < 0)
- writeerr();
- offset += nwritten;
- } while ((n -= nwritten) > 0);
- }
- } while ( stackp > de_stack );
-
- /*
- * Generate the new entry.
- */
- if ( (code=free_ent) < maxmaxcode ) {
- tab_prefixof(code) = (unsigned short)oldcode;
- tab_suffixof(code) = finchar;
- free_ent = code+1;
- }
- /*
- * Remember previous code.
- */
- oldcode = incode;
- }
- /*
- * Flush the stuff remaining in our buffer...
- */
- offset = 0;
- while (n > 0) {
- nwritten = write(fileno(stdout), &buff[offset], n);
- if (nwritten < 0)
- writeerr();
- offset += nwritten;
- n -= nwritten;
- }
-}
-
-/*-
- * Read one code from the standard input. If EOF, return -1.
- * Inputs:
- * stdin
- * Outputs:
- * code or -1 is returned.
- */
-code_int
-getcode() {
- /*
- * On the VAX, it is important to have the register declarations
- * in exactly the order given, or the asm will break.
- */
- register code_int code;
- static int offset = 0, size = 0;
- static char_type buf[BITS];
- register int r_off, bits;
- register char_type *bp = buf;
-
- if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
- /*
- * If the next entry will be too big for the current code
- * size, then we must increase the size. This implies reading
- * a new buffer full, too.
- */
- if ( free_ent > maxcode ) {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode; /* won't get any bigger now */
- else
- maxcode = MAXCODE(n_bits);
- }
- if ( clear_flg > 0) {
- maxcode = MAXCODE (n_bits = INIT_BITS);
- clear_flg = 0;
- }
- size = fread( buf, 1, n_bits, stdin );
- if ( size <= 0 )
- return -1; /* end of file */
- offset = 0;
- /* Round size down to integral number of codes */
- size = (size << 3) - (n_bits - 1);
- }
- r_off = offset;
- bits = n_bits;
-#ifdef vax
- asm( "extzv r10,r9,(r8),r11" );
-#else /* not a vax */
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
- /* Get first part (low order bits) */
-#ifdef NO_UCHAR
- code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
-#else
- code = (*bp++ >> r_off);
-#endif /* NO_UCHAR */
- bits -= (8 - r_off);
- r_off = 8 - r_off; /* now, offset into code word */
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 ) {
-#ifdef NO_UCHAR
- code |= (*bp++ & 0xff) << r_off;
-#else
- code |= *bp++ << r_off;
-#endif /* NO_UCHAR */
- r_off += 8;
- bits -= 8;
- }
- /* high order bits. */
- code |= (*bp & rmask[bits]) << r_off;
-#endif /* vax */
- offset += n_bits;
-
- return code;
-}
-
-#ifdef DEBUG
-printcodes()
-{
- /*
- * Just print out codes from input file. For debugging.
- */
- code_int code;
- int col = 0, bits;
-
- bits = n_bits = INIT_BITS;
- maxcode = MAXCODE(n_bits);
- free_ent = ((block_compress) ? FIRST : 256 );
- while ( ( code = getcode() ) >= 0 ) {
- if ( (code == CLEAR) && block_compress ) {
- free_ent = FIRST - 1;
- clear_flg = 1;
- }
- else if ( free_ent < maxmaxcode )
- free_ent++;
- if ( bits != n_bits ) {
- fprintf(stderr, "\nChange to %d bits\n", n_bits );
- bits = n_bits;
- col = 0;
- }
- fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
- }
- putc( '\n', stderr );
- exit( 0 );
-}
-
-code_int sorttab[1<<BITS]; /* sorted pointers into htab */
-
-dump_tab() /* dump string table */
-{
- register int i, first;
- register ent;
-#define STACK_SIZE 15000
- int stack_top = STACK_SIZE;
- register c;
-
- if(do_decomp == 0) { /* compressing */
- register int flag = 1;
-
- for(i=0; i<hsize; i++) { /* build sort pointers */
- if((long)htabof(i) >= 0) {
- sorttab[codetabof(i)] = i;
- }
- }
- first = block_compress ? FIRST : 256;
- for(i = first; i < free_ent; i++) {
- fprintf(stderr, "%5d: \"", i);
- de_stack[--stack_top] = '\n';
- de_stack[--stack_top] = '"';
- stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff,
- stack_top);
- for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
- ent > 256;
- ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
- stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
- stack_top);
- }
- stack_top = in_stack(ent, stack_top);
- fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
- stack_top = STACK_SIZE;
- }
- } else if(!debug) { /* decompressing */
-
- for ( i = 0; i < free_ent; i++ ) {
- ent = i;
- c = tab_suffixof(ent);
- if ( isascii(c) && isprint(c) )
- fprintf( stderr, "%5d: %5d/'%c' \"",
- ent, tab_prefixof(ent), c );
- else
- fprintf( stderr, "%5d: %5d/\\%03o \"",
- ent, tab_prefixof(ent), c );
- de_stack[--stack_top] = '\n';
- de_stack[--stack_top] = '"';
- for ( ; ent != NULL;
- ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
- stack_top = in_stack(tab_suffixof(ent), stack_top);
- }
- fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
- stack_top = STACK_SIZE;
- }
- }
-}
-
-int
-in_stack(c, stack_top)
- register c, stack_top;
-{
- if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
- de_stack[--stack_top] = c;
- } else {
- switch( c ) {
- case '\n': de_stack[--stack_top] = 'n'; break;
- case '\t': de_stack[--stack_top] = 't'; break;
- case '\b': de_stack[--stack_top] = 'b'; break;
- case '\f': de_stack[--stack_top] = 'f'; break;
- case '\r': de_stack[--stack_top] = 'r'; break;
- case '\\': de_stack[--stack_top] = '\\'; break;
- default:
- de_stack[--stack_top] = '0' + c % 8;
- de_stack[--stack_top] = '0' + (c / 8) % 8;
- de_stack[--stack_top] = '0' + c / 64;
- break;
- }
- de_stack[--stack_top] = '\\';
- }
- return stack_top;
-}
-#endif /* DEBUG */
-
-writeerr()
-{
- (void)fprintf(stderr, "compress: %s: %s\n",
- ofname[0] ? ofname : "stdout", strerror(errno));
- (void)unlink(ofname);
- exit(1);
-}
-
-copystat(ifname, ofname)
-char *ifname, *ofname;
-{
- struct stat statbuf;
- int mode;
- struct utimbuf tp;
-
- fclose(stdout);
- if (stat(ifname, &statbuf)) { /* Get stat on input file */
- perror(ifname);
- return;
- }
- if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
- if(quiet)
- fprintf(stderr, "%s: ", ifname);
- fprintf(stderr, " -- not a regular file: unchanged");
- exit_stat = 1;
- perm_stat = 1;
- } else if (statbuf.st_nlink > 1) {
- if(quiet)
- fprintf(stderr, "%s: ", ifname);
- fprintf(stderr, " -- has %d other links: unchanged",
- statbuf.st_nlink - 1);
- exit_stat = 1;
- perm_stat = 1;
- } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
- if(!quiet)
- fprintf(stderr, " -- file unchanged");
- } else { /* ***** Successful Compression ***** */
- exit_stat = 0;
- mode = statbuf.st_mode & 07777;
- if (chmod(ofname, mode)) /* Copy modes */
- perror(ofname);
- chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */
- tp.actime = statbuf.st_atime;
- tp.modtime = statbuf.st_mtime;
- utime(ofname, &tp); /* Update last accessed and modified times */
- if (unlink(ifname)) /* Remove input file */
- perror(ifname);
- if(!quiet)
- fprintf(stderr, " -- replaced with %s", ofname);
- return; /* Successful return */
- }
-
- /* Unsuccessful return -- one of the tests failed */
- if (unlink(ofname))
- perror(ofname);
-}
-
-void
-onintr ( )
-{
- if (!precious)
- unlink ( ofname );
- exit ( 1 );
-}
-
-void
-oops ( ) /* wild pointer -- assume bad input */
-{
- if ( do_decomp )
- fprintf ( stderr, "uncompress: corrupt input\n" );
- unlink ( ofname );
- exit ( 1 );
-}
-
-cl_block () /* table clear for block compress */
-{
- register long int rat;
-
- checkpoint = in_count + CHECK_GAP;
-#ifdef DEBUG
- if ( debug ) {
- fprintf ( stderr, "count: %ld, ratio: ", in_count );
- prratio ( stderr, in_count, bytes_out );
- fprintf ( stderr, "\n");
- }
-#endif /* DEBUG */
-
- if(in_count > 0x007fffff) { /* shift will overflow */
- rat = bytes_out >> 8;
- if(rat == 0) { /* Don't divide by zero */
- rat = 0x7fffffff;
- } else {
- rat = in_count / rat;
- }
- } else {
- rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
- }
- if ( rat > ratio ) {
- ratio = rat;
- } else {
- ratio = 0;
-#ifdef DEBUG
- if(verbose)
- dump_tab(); /* dump string table */
-#endif
- cl_hash ( (count_int) hsize );
- free_ent = FIRST;
- clear_flg = 1;
- output ( (code_int) CLEAR );
-#ifdef DEBUG
- if(debug)
- fprintf ( stderr, "clear\n" );
-#endif /* DEBUG */
- }
-}
-
-cl_hash(hsize) /* reset code table */
- register count_int hsize;
-{
- register count_int *htab_p = htab+hsize;
- register long i;
- register long m1 = -1;
-
- i = hsize - 16;
- do { /* might use Sys V memset(3) here */
- *(htab_p-16) = m1;
- *(htab_p-15) = m1;
- *(htab_p-14) = m1;
- *(htab_p-13) = m1;
- *(htab_p-12) = m1;
- *(htab_p-11) = m1;
- *(htab_p-10) = m1;
- *(htab_p-9) = m1;
- *(htab_p-8) = m1;
- *(htab_p-7) = m1;
- *(htab_p-6) = m1;
- *(htab_p-5) = m1;
- *(htab_p-4) = m1;
- *(htab_p-3) = m1;
- *(htab_p-2) = m1;
- *(htab_p-1) = m1;
- htab_p -= 16;
- } while ((i -= 16) >= 0);
- for ( i += 16; i > 0; i-- )
- *--htab_p = m1;
-}
-
-prratio(stream, num, den)
-FILE *stream;
-long int num, den;
-{
- register int q; /* Doesn't need to be long */
-
- if(num > 214748L) { /* 2147483647/10000 */
- q = num / (den / 10000L);
- } else {
- q = 10000L * num / den; /* Long calculations, though */
- }
- if (q < 0) {
- putc('-', stream);
- q = -q;
- }
- fprintf(stream, "%d.%02d%%", q / 100, q % 100);
-}
-
-usage()
-{
- (void)fprintf(stderr,
-#ifdef DEBUG
- "compress [-CDVcdfnv] [-b maxbits] [file ...]\n");
-#else
- "compress [-Ccdfnv] [-b maxbits] [file ...]\n");
-#endif
- exit(1);
-}
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index 9388c835b..07b516b4d 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -240,6 +240,7 @@ int main()
#ifndef inet_ntoa_r
func_type func;
func = (func_type)inet_ntoa_r;
+ (void)func;
#endif
return 0;
}
@@ -255,6 +256,7 @@ int main()
#ifndef inet_ntoa_r
func_type func;
func = (func_type)&inet_ntoa_r;
+ (void)func;
#endif
return 0;
}
@@ -553,8 +555,8 @@ main() {
#include <time.h>
int
main() {
- struct timespec ts = {0, 0};
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ struct timespec ts = {0, 0};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
return 0;
}
#endif
@@ -565,3 +567,49 @@ main() {
return 0;
}
#endif
+#ifdef HAVE_VARIADIC_MACROS_C99
+#define c99_vmacro3(first, ...) fun3(first, __VA_ARGS__)
+#define c99_vmacro2(first, ...) fun2(first, __VA_ARGS__)
+
+int fun3(int arg1, int arg2, int arg3);
+int fun2(int arg1, int arg2);
+
+int fun3(int arg1, int arg2, int arg3) {
+ return arg1 + arg2 + arg3;
+}
+int fun2(int arg1, int arg2) {
+ return arg1 + arg2;
+}
+
+int
+main() {
+ int res3 = c99_vmacro3(1, 2, 3);
+ int res2 = c99_vmacro2(1, 2);
+ (void)res3;
+ (void)res2;
+ return 0;
+}
+#endif
+#ifdef HAVE_VARIADIC_MACROS_GCC
+#define gcc_vmacro3(first, args...) fun3(first, args)
+#define gcc_vmacro2(first, args...) fun2(first, args)
+
+int fun3(int arg1, int arg2, int arg3);
+int fun2(int arg1, int arg2);
+
+int fun3(int arg1, int arg2, int arg3) {
+ return arg1 + arg2 + arg3;
+}
+int fun2(int arg1, int arg2) {
+ return arg1 + arg2;
+}
+
+int
+main() {
+ int res3 = gcc_vmacro3(1, 2, 3);
+ int res2 = gcc_vmacro2(1, 2);
+ (void)res3;
+ (void)res2;
+ return 0;
+}
+#endif
diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake
index 7a637fc29..8a28f2fb6 100644
--- a/Utilities/cmcurl/CMake/FindGSS.cmake
+++ b/Utilities/cmcurl/CMake/FindGSS.cmake
@@ -68,7 +68,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
# should also work in an odd case when multiple directories are given
string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
- string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1"_GSS_CFLAGS "${_GSS_CFLAGS}")
+ string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
foreach(_flag ${_GSS_CFLAGS})
if(_flag MATCHES "^-I.*")
@@ -91,7 +91,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
# this script gives us libraries and link directories. Blah. We have to deal with it.
string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
- string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1"_GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
+ string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
foreach(_flag ${_GSS_LIB_FLAGS})
if(_flag MATCHES "^-l.*")
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index ce6d3e13a..c1c9aa32a 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -24,6 +24,8 @@ else()
add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
endif()
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
check_c_source_compiles("${_source_epilogue}
int main(void) {
recv(0, 0, 0, 0);
@@ -177,23 +179,6 @@ int main(void) {
return 0;
}" HAVE_STRUCT_TIMEVAL)
-
-include(CheckCSourceRuns)
-# See HAVE_POLL in CMakeLists.txt for why poll is disabled on macOS
-if(NOT APPLE)
- set(CMAKE_REQUIRED_FLAGS)
- if(HAVE_SYS_POLL_H)
- set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
- endif()
- check_c_source_runs("
- #ifdef HAVE_SYS_POLL_H
- # include <sys/poll.h>
- #endif
- int main(void) {
- return poll((void *)0, 0, 10 /*ms*/);
- }" HAVE_POLL_FINE)
-endif()
-
set(HAVE_SIG_ATOMIC_T 1)
set(CMAKE_REQUIRED_FLAGS)
if(HAVE_SIGNAL_H)
@@ -229,3 +214,51 @@ check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
endif()
+
+unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ # if not cross-compilation...
+ include(CheckCSourceRuns)
+ set(CMAKE_REQUIRED_FLAGS "")
+ if(HAVE_SYS_POLL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
+ elseif(HAVE_POLL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_POLL_H")
+ endif()
+ check_c_source_runs("
+ #include <stdlib.h>
+ #include <sys/time.h>
+
+ #ifdef HAVE_SYS_POLL_H
+ # include <sys/poll.h>
+ #elif HAVE_POLL_H
+ # include <poll.h>
+ #endif
+
+ int main(void)
+ {
+ if(0 != poll(0, 0, 10)) {
+ return 1; /* fail */
+ }
+ else {
+ /* detect the 10.12 poll() breakage */
+ struct timeval before, after;
+ int rc;
+ size_t us;
+
+ gettimeofday(&before, NULL);
+ rc = poll(NULL, 0, 500);
+ gettimeofday(&after, NULL);
+
+ us = (after.tv_sec - before.tv_sec) * 1000000 +
+ (after.tv_usec - before.tv_usec);
+
+ if(us < 400000) {
+ return 1;
+ }
+ }
+ return 0;
+ }" HAVE_POLL_FINE)
+endif()
+
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 1c96497cd..37522fc10 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -53,10 +53,11 @@ elseif(APPLE)
endif()
if(NOT OSX_VERSION VERSION_LESS 10.6 AND
CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
- set(CMAKE_USE_DARWINSSL ON CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ set(CMAKE_USE_SECTRANSP ON CACHE INTERNAL "enable Apple OS native SSL/TLS")
else()
- set(CMAKE_USE_DARWINSSL OFF CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ set(CMAKE_USE_SECTRANSP OFF CACHE INTERNAL "enable Apple OS native SSL/TLS")
endif()
+ unset(CMAKE_USE_DARWINSSL CACHE)
endif()
set(CMAKE_USE_MBEDTLS OFF CACHE INTERNAL "Enable mbedTLS for SSL/TLS")
@@ -77,7 +78,7 @@ endif(APPLE)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -90,7 +91,7 @@ endif()
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2019, 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
@@ -143,7 +144,6 @@ string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+"
CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS})
string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})
-include_regular_expression("^.*$") # Sukender: Is it necessary?
# Setup package meta-data
# SET(PACKAGE "curl")
@@ -158,7 +158,6 @@ endif()
set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
set(OS "\"${CMAKE_SYSTEM_NAME}\"")
-include_directories(${PROJECT_BINARY_DIR}/include/curl)
include_directories(${CURL_SOURCE_DIR}/include)
option(CURL_WERROR "Turn compiler warnings into errors" OFF)
@@ -171,9 +170,11 @@ if(WIN32)
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)
endif()
+if(0) # This code not needed for building within CMake.
cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
ON "NOT ENABLE_ARES"
OFF)
+endif()
option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
@@ -193,11 +194,7 @@ endif()
if(ENABLE_DEBUG)
# DEBUGBUILD will be defined only for Debug builds
- if(NOT CMAKE_VERSION VERSION_LESS 3.0)
- set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
- else()
- set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD)
- endif()
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
set(ENABLE_CURLDEBUG ON)
endif()
@@ -393,10 +390,10 @@ if(WIN32)
endif()
# check SSL libraries
-# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL
+# TODO support GNUTLS, NSS, POLARSSL, CYASSL
if(APPLE)
- option(CMAKE_USE_DARWINSSL "enable Apple OS native SSL/TLS" OFF)
+ option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
endif()
if(WIN32)
option(CMAKE_USE_WINSSL "enable Windows native SSL/TLS" OFF)
@@ -406,13 +403,13 @@ endif()
option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
set(openssl_default ON)
-if(WIN32 OR CMAKE_USE_DARWINSSL OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS)
+if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS)
set(openssl_default OFF)
endif()
count_true(enabled_ssl_options_count
CMAKE_USE_WINSSL
- CMAKE_USE_DARWINSSL
+ CMAKE_USE_SECTRANSP
CMAKE_USE_OPENSSL
CMAKE_USE_MBEDTLS
)
@@ -432,6 +429,10 @@ if(CURL_WINDOWS_SSPI)
endif()
if(CMAKE_USE_DARWINSSL)
+ message(FATAL_ERROR "The cmake option CMAKE_USE_DARWINSSL was renamed to CMAKE_USE_SECTRANSP.")
+endif()
+
+if(CMAKE_USE_SECTRANSP)
find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
if(NOT COREFOUNDATION_FRAMEWORK)
message(FATAL_ERROR "CoreFoundation framework not found")
@@ -443,7 +444,7 @@ if(CMAKE_USE_DARWINSSL)
endif()
set(SSL_ENABLED ON)
- set(USE_DARWINSSL ON)
+ set(USE_SECTRANSP ON)
list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}")
endif()
@@ -578,6 +579,7 @@ if(NOT CURL_DISABLE_LDAP)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
endif()
check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
+ unset(CMAKE_REQUIRED_LIBRARIES)
if(NOT_NEED_LBER_H)
set(NEED_LBER_H OFF)
@@ -685,6 +687,7 @@ if(CMAKE_USE_LIBSSH2)
check_function_exists(libssh2_scp_send64 HAVE_LIBSSH2_SCP_SEND64)
check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE)
set(CMAKE_EXTRA_INCLUDE_FILES "")
+ unset(CMAKE_REQUIRED_LIBRARIES)
endif()
endif()
@@ -699,7 +702,7 @@ if(CMAKE_USE_GSSAPI)
message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"")
- list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES})
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR})
check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H)
check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
@@ -732,10 +735,11 @@ if(CMAKE_USE_GSSAPI)
if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
set(HAVE_OLD_GSSMIT ON)
endif()
+ unset(CMAKE_REQUIRED_LIBRARIES)
endif()
- include_directories(${GSS_INCLUDE_DIRECTORIES})
+ include_directories(${GSS_INCLUDE_DIR})
link_directories(${GSS_LINK_DIRECTORIES})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
@@ -942,12 +946,8 @@ endif()
check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME)
check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET)
-# poll on macOS is unreliable, it first did not exist, then was broken until
-# fixed in 10.9 only to break again in 10.12.
-if(NOT APPLE)
- check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL)
-endif()
check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT)
+check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL)
check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP)
check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR)
check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R)
@@ -1003,6 +1003,8 @@ check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS)
check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE)
check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE)
check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
+check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME)
+check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT)
check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE)
check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE)
@@ -1086,6 +1088,8 @@ foreach(CURL_TEST
HAVE_INET_NTOA_R_DECL_REENTRANT
HAVE_GETADDRINFO
HAVE_FILE_OFFSET_BITS
+ HAVE_VARIADIC_MACROS_C99
+ HAVE_VARIADIC_MACROS_GCC
)
curl_internal_test(${CURL_TEST})
endforeach()
@@ -1247,7 +1251,7 @@ if(CURL_WERROR)
endif()
# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
-function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
+function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
@@ -1311,10 +1315,7 @@ endfunction()
# Clear list and try to detect available features
set(_items)
-_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI)
-_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL)
-_add_if("DarwinSSL" SSL_ENABLED AND USE_DARWINSSL)
-_add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS)
+_add_if("SSL" SSL_ENABLED)
_add_if("IPv6" ENABLE_IPV6)
_add_if("unix-sockets" USE_UNIX_SOCKETS)
_add_if("libz" HAVE_LIBZ)
@@ -1332,7 +1333,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
-if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS))
+if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_SECTRANSP OR USE_MBEDTLS))
_add_if("NTLM" 1)
# TODO missing option (autoconf: --enable-ntlm-wb)
_add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
@@ -1371,10 +1372,24 @@ _add_if("SCP" USE_LIBSSH2)
_add_if("SFTP" USE_LIBSSH2)
_add_if("RTSP" NOT CURL_DISABLE_RTSP)
_add_if("RTMP" USE_LIBRTMP)
-list(SORT _items)
+if(_items)
+ list(SORT _items)
+endif()
string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")
message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")
+# Clear list and collect SSL backends
+set(_items)
+_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI)
+_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL)
+_add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
+_add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS)
+if(_items)
+ list(SORT _items)
+endif()
+string(REPLACE ";" " " SSL_BACKENDS "${_items}")
+message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
+
# curl-config needs the following options to be set.
set(CC "${CMAKE_C_COMPILER}")
# TODO probably put a -D... options here?
diff --git a/Utilities/cmcurl/COPYING b/Utilities/cmcurl/COPYING
index 560a49dce..3528bd756 100644
--- a/Utilities/cmcurl/COPYING
+++ b/Utilities/cmcurl/COPYING
@@ -1,6 +1,6 @@
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2018, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2019, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index 63bb291b3..089c427db 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -91,6 +91,11 @@
#include <support/SupportDefs.h>
#endif
+/* Compatibility for non-Clang compilers */
+#ifndef __has_declspec_attribute
+# define __has_declspec_attribute(x) 0
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -109,7 +114,9 @@ typedef void CURLSH;
#ifdef CURL_STATICLIB
# define CURL_EXTERN
-#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
+#elif defined(WIN32) || defined(__SYMBIAN32__) || \
+ (__has_declspec_attribute(dllexport) && \
+ __has_declspec_attribute(dllimport))
# if defined(BUILDING_LIBCURL)
# define CURL_EXTERN __declspec(dllexport)
# else
@@ -144,8 +151,8 @@ typedef enum {
CURLSSLBACKEND_POLARSSL = 6,
CURLSSLBACKEND_WOLFSSL = 7,
CURLSSLBACKEND_SCHANNEL = 8,
- CURLSSLBACKEND_DARWINSSL = 9,
- CURLSSLBACKEND_AXTLS = 10,
+ CURLSSLBACKEND_SECURETRANSPORT = 9,
+ CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
CURLSSLBACKEND_MBEDTLS = 11,
CURLSSLBACKEND_MESALINK = 12
} curl_sslbackend;
@@ -153,7 +160,10 @@ typedef enum {
/* aliases for library clones and renames */
#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL
+
+/* deprecated names: */
#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
+#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT
struct curl_httppost {
struct curl_httppost *next; /* next entry in the list */
@@ -280,7 +290,7 @@ typedef enum {
struct curl_fileinfo {
char *filename;
curlfiletype filetype;
- time_t time;
+ time_t time; /* always zero! */
unsigned int perm;
int uid;
int gid;
@@ -355,11 +365,21 @@ typedef int (*curl_seek_callback)(void *instream,
signal libcurl to pause sending data on the current transfer. */
#define CURL_READFUNC_PAUSE 0x10000001
+/* Return code for when the trailing headers' callback has terminated
+ without any errors*/
+#define CURL_TRAILERFUNC_OK 0
+/* Return code for when was an error in the trailing header's list and we
+ want to abort the request */
+#define CURL_TRAILERFUNC_ABORT 1
+
typedef size_t (*curl_read_callback)(char *buffer,
size_t size,
size_t nitems,
void *instream);
+typedef int (*curl_trailer_callback)(struct curl_slist **list,
+ void *userdata);
+
typedef enum {
CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
@@ -585,9 +605,6 @@ typedef enum {
CURL_LAST /* never use! */
} CURLcode;
-/* added in 7.62.0 */
-#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION
-
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
the obsolete stuff removed! */
@@ -602,6 +619,9 @@ typedef enum {
#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY
+/* The following were added in 7.62.0 */
+#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION
+
/* The following were added in 7.21.5, April 2011 */
#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
@@ -861,6 +881,14 @@ typedef enum {
#define CURLHEADER_UNIFIED 0
#define CURLHEADER_SEPARATE (1<<0)
+/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */
+#define CURLALTSVC_IMMEDIATELY (1<<0)
+#define CURLALTSVC_ALTUSED (1<<1)
+#define CURLALTSVC_READONLYFILE (1<<2)
+#define CURLALTSVC_H1 (1<<3)
+#define CURLALTSVC_H2 (1<<4)
+#define CURLALTSVC_H3 (1<<5)
+
/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
#define CURLPROTO_HTTP (1<<0)
#define CURLPROTO_HTTPS (1<<1)
@@ -1872,6 +1900,27 @@ typedef enum {
/* Time in ms between connection upkeep calls for long-lived connections. */
CINIT(UPKEEP_INTERVAL_MS, LONG, 281),
+ /* Specify URL using CURL URL API. */
+ CINIT(CURLU, OBJECTPOINT, 282),
+
+ /* add trailing data just after no more data is available */
+ CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 283),
+
+ /* pointer to be passed to HTTP_TRAILER_FUNCTION */
+ CINIT(TRAILERDATA, OBJECTPOINT, 284),
+
+ /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
+ CINIT(HTTP09_ALLOWED, LONG, 285),
+
+ /* alt-svc control bitmask */
+ CINIT(ALTSVC_CTRL, LONG, 286),
+
+ /* alt-svc cache file name to possibly read from/write to */
+ CINIT(ALTSVC, STRINGPOINT, 287),
+
+ /* maximum age of a connection to consider it for reuse (in seconds) */
+ CINIT(MAXAGE_CONN, LONG, 288),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2734,6 +2783,7 @@ typedef struct {
#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */
#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */
#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */
+#define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */
/*
* NAME curl_version_info()
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index 3d7b1fbfe..04efb93ae 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -26,16 +26,16 @@
a script at release-time. This was made its own header file in 7.11.2 */
/* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2018 Daniel Stenberg, <daniel@haxx.se>."
+#define LIBCURL_COPYRIGHT "1996 - 2019 Daniel Stenberg, <daniel@haxx.se>."
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "7.62.0"
+#define LIBCURL_VERSION "7.65.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 62
+#define LIBCURL_VERSION_MINOR 65
#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 0x073E00
+#define LIBCURL_VERSION_NUM 0x074100
/*
* This is the date and time when the full source package was created. The
@@ -70,7 +70,7 @@
*/
#define LIBCURL_TIMESTAMP "[unreleased]"
-#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z)
+#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
#define CURL_AT_LEAST_VERSION(x,y,z) \
(LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h
index 244336204..2d1de4d43 100644
--- a/Utilities/cmcurl/include/curl/typecheck-gcc.h
+++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -113,7 +113,6 @@ __extension__ ({ \
})
/* wraps curl_easy_getinfo() with typechecking */
-/* FIXME: don't allow const pointers */
#define curl_easy_getinfo(handle, info, arg) \
__extension__ ({ \
__typeof__(info) _curl_info = info; \
@@ -146,9 +145,8 @@ __extension__ ({ \
curl_easy_getinfo(handle, _curl_info, arg); \
})
-/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
- * for now just make sure that the functions are called with three
- * arguments
+/*
+ * For now, just make sure that the functions are called with three arguments
*/
#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
@@ -256,6 +254,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
#define _curl_is_string_option(option) \
((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
(option) == CURLOPT_ACCEPT_ENCODING || \
+ (option) == CURLOPT_ALTSVC || \
(option) == CURLOPT_CAINFO || \
(option) == CURLOPT_CAPATH || \
(option) == CURLOPT_COOKIE || \
@@ -363,6 +362,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SSL_CTX_DATA || \
(option) == CURLOPT_WRITEDATA || \
(option) == CURLOPT_RESOLVER_START_DATA || \
+ (option) == CURLOPT_CURLU || \
0)
/* evaluates to true if option takes a POST data argument (void* or char*) */
@@ -504,10 +504,6 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
_curl_is_arr((expr), char) || \
_curl_is_arr((expr), unsigned char))
-/* FIXME: the whole callback checking is messy...
- * The idea is to tolerate char vs. void and const vs. not const
- * pointers in arguments at least
- */
/* helper: __builtin_types_compatible_p distinguishes between functions and
* function pointers, hide it */
#define _curl_callback_compatible(func, type) \
diff --git a/Utilities/cmcurl/include/curl/urlapi.h b/Utilities/cmcurl/include/curl/urlapi.h
index 90dd56c00..58e89d85c 100644
--- a/Utilities/cmcurl/include/curl/urlapi.h
+++ b/Utilities/cmcurl/include/curl/urlapi.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2019, 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
@@ -22,6 +22,8 @@
*
***************************************************************************/
+#include "curl.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -58,7 +60,8 @@ typedef enum {
CURLUPART_PORT,
CURLUPART_PATH,
CURLUPART_QUERY,
- CURLUPART_FRAGMENT
+ CURLUPART_FRAGMENT,
+ CURLUPART_ZONEID /* added in 7.65.0 */
} CURLUPart;
#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index 4aa042259..235b82b0e 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2019, 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
@@ -28,13 +28,13 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \
LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
- vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \
+ vtls/polarssl.c vtls/polarssl_threadlock.c \
vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \
- vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c
+ vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c
LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \
- vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \
- vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \
+ vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \
+ vtls/cyassl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \
vtls/mbedtls.h vtls/mesalink.h
LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
@@ -52,10 +52,10 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
openldap.c curl_gethostname.c gopher.c idn_win32.c \
http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \
http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \
- curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
+ curl_multibyte.c hostcheck.c conncache.c dotdot.c \
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
- doh.c urlapi.c
+ doh.c urlapi.c curl_get_line.c altsvc.c
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
@@ -72,10 +72,11 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \
http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \
curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \
- curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
+ curl_setup_once.h multihandle.h setup-vms.h dotdot.h \
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
- curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h
+ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \
+ curl_get_line.h altsvc.h
LIB_RCFILES = libcurl.rc
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
new file mode 100644
index 000000000..85a4e01b5
--- /dev/null
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -0,0 +1,569 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2019, 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.
+ *
+ ***************************************************************************/
+/*
+ * The Alt-Svc: header is defined in RFC 7838:
+ * https://tools.ietf.org/html/rfc7838
+ */
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC)
+#include <curl/curl.h>
+#include "urldata.h"
+#include "altsvc.h"
+#include "curl_get_line.h"
+#include "strcase.h"
+#include "parsedate.h"
+#include "sendf.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MAX_ALTSVC_LINE 4095
+#define MAX_ALTSVC_DATELENSTR "64"
+#define MAX_ALTSVC_DATELEN 64
+#define MAX_ALTSVC_HOSTLENSTR "512"
+#define MAX_ALTSVC_HOSTLEN 512
+#define MAX_ALTSVC_ALPNLENSTR "10"
+#define MAX_ALTSVC_ALPNLEN 10
+
+static enum alpnid alpn2alpnid(char *name)
+{
+ if(strcasecompare(name, "h1"))
+ return ALPN_h1;
+ if(strcasecompare(name, "h2"))
+ return ALPN_h2;
+ if(strcasecompare(name, "h2c"))
+ return ALPN_h2c;
+ if(strcasecompare(name, "h3"))
+ return ALPN_h3;
+ return ALPN_none; /* unknown, probably rubbish input */
+}
+
+/* Given the ALPN ID, return the name */
+const char *Curl_alpnid2str(enum alpnid id)
+{
+ switch(id) {
+ case ALPN_h1:
+ return "h1";
+ case ALPN_h2:
+ return "h2";
+ case ALPN_h2c:
+ return "h2c";
+ case ALPN_h3:
+ return "h3";
+ default:
+ return ""; /* bad */
+ }
+}
+
+
+static void altsvc_free(struct altsvc *as)
+{
+ free(as->srchost);
+ free(as->dsthost);
+ free(as);
+}
+
+static struct altsvc *altsvc_createid(const char *srchost,
+ const char *dsthost,
+ enum alpnid srcalpnid,
+ enum alpnid dstalpnid,
+ unsigned int srcport,
+ unsigned int dstport)
+{
+ struct altsvc *as = calloc(sizeof(struct altsvc), 1);
+ if(!as)
+ return NULL;
+
+ as->srchost = strdup(srchost);
+ if(!as->srchost)
+ goto error;
+ as->dsthost = strdup(dsthost);
+ if(!as->dsthost)
+ goto error;
+
+ as->srcalpnid = srcalpnid;
+ as->dstalpnid = dstalpnid;
+ as->srcport = curlx_ultous(srcport);
+ as->dstport = curlx_ultous(dstport);
+
+ return as;
+ error:
+ altsvc_free(as);
+ return NULL;
+}
+
+static struct altsvc *altsvc_create(char *srchost,
+ char *dsthost,
+ char *srcalpn,
+ char *dstalpn,
+ unsigned int srcport,
+ unsigned int dstport)
+{
+ enum alpnid dstalpnid = alpn2alpnid(dstalpn);
+ enum alpnid srcalpnid = alpn2alpnid(srcalpn);
+ if(!srcalpnid || !dstalpnid)
+ return NULL;
+ return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid,
+ srcport, dstport);
+}
+
+/* only returns SERIOUS errors */
+static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+{
+ /* Example line:
+ h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
+ */
+ char srchost[MAX_ALTSVC_HOSTLEN + 1];
+ char dsthost[MAX_ALTSVC_HOSTLEN + 1];
+ char srcalpn[MAX_ALTSVC_ALPNLEN + 1];
+ char dstalpn[MAX_ALTSVC_ALPNLEN + 1];
+ char date[MAX_ALTSVC_DATELEN + 1];
+ unsigned int srcport;
+ unsigned int dstport;
+ unsigned int prio;
+ unsigned int persist;
+ int rc;
+
+ rc = sscanf(line,
+ "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
+ "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
+ "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u",
+ srcalpn, srchost, &srcport,
+ dstalpn, dsthost, &dstport,
+ date, &persist, &prio);
+ if(9 == rc) {
+ struct altsvc *as;
+ time_t expires = curl_getdate(date, NULL);
+ as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport);
+ if(as) {
+ as->expires = expires;
+ as->prio = prio;
+ as->persist = persist ? 1 : 0;
+ Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+ asi->num++; /* one more entry */
+ }
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Load alt-svc entries from the given file. The text based line-oriented file
+ * format is documented here:
+ * https://github.com/curl/curl/wiki/QUIC-implementation
+ *
+ * This function only returns error on major problems that prevents alt-svc
+ * handling to work completely. It will ignore individual syntactical errors
+ * etc.
+ */
+static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+{
+ CURLcode result = CURLE_OK;
+ char *line = NULL;
+ FILE *fp = fopen(file, FOPEN_READTEXT);
+ if(fp) {
+ line = malloc(MAX_ALTSVC_LINE);
+ if(!line)
+ goto fail;
+ while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) {
+ char *lineptr = line;
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+ if(*lineptr == '#')
+ /* skip commented lines */
+ continue;
+
+ altsvc_add(asi, lineptr);
+ }
+ free(line); /* free the line buffer */
+ fclose(fp);
+ }
+ return result;
+
+ fail:
+ free(line);
+ fclose(fp);
+ return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * Write this single altsvc entry to a single output line
+ */
+
+static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
+{
+ struct tm stamp;
+ CURLcode result = Curl_gmtime(as->expires, &stamp);
+ if(result)
+ return result;
+
+ fprintf(fp,
+ "%s %s %u "
+ "%s %s %u "
+ "\"%d%02d%02d "
+ "%02d:%02d:%02d\" "
+ "%u %d\n",
+ Curl_alpnid2str(as->srcalpnid), as->srchost, as->srcport,
+ Curl_alpnid2str(as->dstalpnid), as->dsthost, as->dstport,
+ stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+ stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
+ as->persist, as->prio);
+ return CURLE_OK;
+}
+
+/* ---- library-wide functions below ---- */
+
+/*
+ * Curl_altsvc_init() creates a new altsvc cache.
+ * It returns the new instance or NULL if something goes wrong.
+ */
+struct altsvcinfo *Curl_altsvc_init(void)
+{
+ struct altsvcinfo *asi = calloc(sizeof(struct altsvcinfo), 1);
+ if(!asi)
+ return NULL;
+ Curl_llist_init(&asi->list, NULL);
+
+ /* set default behavior */
+ asi->flags = CURLALTSVC_H1
+#ifdef USE_NGHTTP2
+ | CURLALTSVC_H2
+#endif
+#ifdef USE_HTTP3
+ | CURLALTSVC_H3
+#endif
+ ;
+ return asi;
+}
+
+/*
+ * Curl_altsvc_load() loads alt-svc from file.
+ */
+CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
+{
+ CURLcode result;
+ DEBUGASSERT(asi);
+ result = altsvc_load(asi, file);
+ return result;
+}
+
+/*
+ * Curl_altsvc_ctrl() passes on the external bitmask.
+ */
+CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
+{
+ DEBUGASSERT(asi);
+ if(!ctrl)
+ /* unexpected */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ asi->flags = ctrl;
+ return CURLE_OK;
+}
+
+/*
+ * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
+ * resources.
+ */
+void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
+{
+ struct curl_llist_element *e;
+ struct curl_llist_element *n;
+ if(altsvc) {
+ for(e = altsvc->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
+ altsvc_free(as);
+ }
+ free(altsvc);
+ }
+}
+
+/*
+ * Curl_altsvc_save() writes the altsvc cache to a file.
+ */
+CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file)
+{
+ struct curl_llist_element *e;
+ struct curl_llist_element *n;
+ CURLcode result = CURLE_OK;
+ FILE *out;
+
+ if(!altsvc)
+ /* no cache activated */
+ return CURLE_OK;
+
+ if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file[0])
+ /* marked as read-only or zero length file name */
+ return CURLE_OK;
+ out = fopen(file, FOPEN_WRITETEXT);
+ if(!out)
+ return CURLE_WRITE_ERROR;
+ fputs("# Your alt-svc cache. https://curl.haxx.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) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
+ result = altsvc_out(as, out);
+ if(result)
+ break;
+ }
+ fclose(out);
+ return result;
+}
+
+static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
+{
+ size_t len;
+ const char *protop;
+ const char *p = *ptr;
+ while(*p && ISBLANK(*p))
+ p++;
+ protop = p;
+ while(*p && ISALNUM(*p))
+ p++;
+ len = p - protop;
+
+ if(!len || (len >= buflen))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ memcpy(alpnbuf, protop, len);
+ alpnbuf[len] = 0;
+ *ptr = p;
+ return CURLE_OK;
+}
+
+/* altsvc_flush() removes all alternatives for this source origin from the
+ list */
+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;
+ for(e = asi->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
+ if((srcalpnid == as->srcalpnid) &&
+ (srcport == as->srcport) &&
+ strcasecompare(srchost, as->srchost)) {
+ Curl_llist_remove(&asi->list, e, NULL);
+ altsvc_free(as);
+ asi->num--;
+ }
+ }
+}
+
+#ifdef DEBUGBUILD
+/* to play well with debug builds, we can *set* a fixed time this will
+ return */
+static time_t debugtime(void *unused)
+{
+ char *timestr = getenv("CURL_TIME");
+ (void)unused;
+ if(timestr) {
+ unsigned long val = strtol(timestr, NULL, 10);
+ return (time_t)val;
+ }
+ return time(NULL);
+}
+#define time(x) debugtime(x)
+#endif
+
+/*
+ * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
+ * the data correctly in the cache.
+ *
+ * 'value' points to the header *value*. That's contents to the right of the
+ * header name.
+ */
+CURLcode Curl_altsvc_parse(struct Curl_easy *data,
+ struct altsvcinfo *asi, const char *value,
+ enum alpnid srcalpnid, const char *srchost,
+ unsigned short srcport)
+{
+ 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 */
+ const char *semip;
+ time_t maxage = 24 * 3600; /* default is 24 hours */
+ bool persist = FALSE;
+ CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
+ if(result)
+ return result;
+
+ DEBUGASSERT(asi);
+
+ /* Flush all cached alternatives for this source origin, if any */
+ altsvc_flush(asi, srcalpnid, srchost, srcport);
+
+ /* "clear" is a magic keyword */
+ if(strcasecompare(alpnbuf, "clear")) {
+ return CURLE_OK;
+ }
+
+ /* The 'ma' and 'persist' flags are annoyingly meant for all alternatives
+ but are set after the list on the line. Scan for the semicolons and get
+ those fields first! */
+ semip = p;
+ do {
+ semip = strchr(semip, ';');
+ if(semip) {
+ char option[32];
+ unsigned long num;
+ char *end_ptr;
+ semip++; /* pass the semicolon */
+ result = getalnum(&semip, option, sizeof(option));
+ if(result)
+ break;
+ while(*semip && ISBLANK(*semip))
+ semip++;
+ if(*semip != '=')
+ continue;
+ semip++;
+ num = strtoul(semip, &end_ptr, 10);
+ if(num < ULONG_MAX) {
+ if(strcasecompare("ma", option))
+ maxage = num;
+ else if(strcasecompare("persist", option) && (num == 1))
+ persist = TRUE;
+ }
+ semip = end_ptr;
+ }
+ } while(semip);
+
+ do {
+ if(*p == '=') {
+ /* [protocol]="[host][:port]" */
+ dstalpnid = alpn2alpnid(alpnbuf);
+ if(!dstalpnid) {
+ infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf);
+ return CURLE_OK;
+ }
+ p++;
+ if(*p == '\"') {
+ const char *dsthost;
+ p++;
+ if(*p != ':') {
+ /* host name starts here */
+ const char *hostp = p;
+ while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
+ p++;
+ len = p - hostp;
+ if(!len || (len >= MAX_ALTSVC_HOSTLEN))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ memcpy(namebuf, hostp, len);
+ namebuf[len] = 0;
+ dsthost = namebuf;
+ }
+ else {
+ /* no destination name, use source host */
+ dsthost = srchost;
+ }
+ if(*p == ':') {
+ /* a port number */
+ char *end_ptr;
+ unsigned long port = strtoul(++p, &end_ptr, 10);
+ if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
+ infof(data, "Unknown alt-svc port number, ignoring...\n");
+ return CURLE_OK;
+ }
+ p = end_ptr;
+ dstport = curlx_ultous(port);
+ }
+ if(*p++ != '\"')
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ as = altsvc_createid(srchost, dsthost,
+ srcalpnid, dstalpnid,
+ srcport, dstport);
+ if(as) {
+ /* The expires time also needs to take the Age: value (if any) into
+ account. [See RFC 7838 section 3.1] */
+ as->expires = maxage + time(NULL);
+ as->persist = persist;
+ Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+ asi->num++; /* one more entry */
+ infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
+ Curl_alpnid2str(dstalpnid));
+ }
+ }
+ /* after the double quote there can be a comma if there's another
+ string or a semicolon if no more */
+ if(*p == ',') {
+ /* comma means another alternative is presented */
+ p++;
+ result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
+ if(result)
+ /* failed to parse, but since we already did at least one host we
+ return OK */
+ return CURLE_OK;
+ }
+ }
+ } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
+
+ return CURLE_OK;
+}
+
+/*
+ * Return TRUE on a match
+ */
+bool Curl_altsvc_lookup(struct altsvcinfo *asi,
+ enum alpnid srcalpnid, const char *srchost,
+ int srcport,
+ enum alpnid *dstalpnid, const char **dsthost,
+ int *dstport)
+{
+ struct curl_llist_element *e;
+ struct curl_llist_element *n;
+ time_t now = time(NULL);
+ DEBUGASSERT(asi);
+ DEBUGASSERT(srchost);
+ DEBUGASSERT(dsthost);
+
+ for(e = asi->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
+ if(as->expires < now) {
+ /* an expired entry, remove */
+ altsvc_free(as);
+ continue;
+ }
+ if((as->srcalpnid == srcalpnid) &&
+ strcasecompare(as->srchost, srchost) &&
+ as->srcport == srcport) {
+ /* match */
+ *dstalpnid = as->dstalpnid;
+ *dsthost = as->dsthost;
+ *dstport = as->dstport;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
diff --git a/Utilities/cmcurl/lib/altsvc.h b/Utilities/cmcurl/lib/altsvc.h
new file mode 100644
index 000000000..eefb45bf6
--- /dev/null
+++ b/Utilities/cmcurl/lib/altsvc.h
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_ALTSVC_H
+#define HEADER_CURL_ALTSVC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2019, 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_ALTSVC)
+#include <curl/curl.h>
+#include "llist.h"
+
+enum alpnid {
+ ALPN_none,
+ ALPN_h1,
+ ALPN_h2,
+ ALPN_h2c,
+ ALPN_h3
+};
+
+struct altsvc {
+ char *srchost;
+ char *dsthost;
+ unsigned short srcport;
+ unsigned short dstport;
+ enum alpnid srcalpnid;
+ enum alpnid dstalpnid;
+ time_t expires;
+ bool persist;
+ int prio;
+ struct curl_llist_element node;
+};
+
+struct altsvcinfo {
+ char *filename;
+ struct curl_llist list; /* list of entries */
+ size_t num; /* number of alt-svc entries */
+ long flags; /* the publicly set bitmask */
+};
+
+const char *Curl_alpnid2str(enum alpnid id);
+struct altsvcinfo *Curl_altsvc_init(void);
+CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file);
+CURLcode Curl_altsvc_save(struct altsvcinfo *asi, const char *file);
+CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl);
+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,
+ unsigned short srcport);
+bool Curl_altsvc_lookup(struct altsvcinfo *asi,
+ enum alpnid srcalpnid, const char *srchost,
+ int srcport,
+ enum alpnid *dstalpnid, const char **dsthost,
+ int *dstport);
+#else
+/* disabled */
+#define Curl_altsvc_save(a,b)
+#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
+#endif /* HEADER_CURL_ALTSVC_H */
diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c
index 4f55b30e7..cf44bdc8d 100644
--- a/Utilities/cmcurl/lib/amigaos.c
+++ b/Utilities/cmcurl/lib/amigaos.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,17 +22,26 @@
#include "curl_setup.h"
-#if defined(__AMIGA__) && !defined(__ixemul__)
-
-#include <amitcp/socketbasetags.h>
+#ifdef __AMIGA__
+# include "amigaos.h"
+# if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL)
+# include <amitcp/socketbasetags.h>
+# endif
+# ifdef __libnix__
+# include <stabs.h>
+# endif
+#endif
-#include "amigaos.h"
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+#ifdef __AMIGA__
+#if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL)
struct Library *SocketBase = NULL;
extern int errno, h_errno;
#ifdef __libnix__
-#include <stabs.h>
void __request(const char *msg);
#else
# define __request(msg) Printf(msg "\n\a")
@@ -74,4 +83,13 @@ bool Curl_amiga_init()
ADD2EXIT(Curl_amiga_cleanup, -50);
#endif
-#endif /* __AMIGA__ && ! __ixemul__ */
+#endif /* HAVE_PROTO_BSDSOCKET_H */
+
+#ifdef USE_AMISSL
+void Curl_amiga_X509_free(X509 *a)
+{
+ X509_free(a);
+}
+#endif /* USE_AMISSL */
+#endif /* __AMIGA__ */
+
diff --git a/Utilities/cmcurl/lib/amigaos.h b/Utilities/cmcurl/lib/amigaos.h
index 7c0926cc3..c776c9c9b 100644
--- a/Utilities/cmcurl/lib/amigaos.h
+++ b/Utilities/cmcurl/lib/amigaos.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -23,7 +23,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(__AMIGA__) && !defined(__ixemul__)
+#if defined(__AMIGA__) && defined(HAVE_BSDSOCKET_H) && !defined(USE_AMISSL)
bool Curl_amiga_init();
void Curl_amiga_cleanup();
@@ -35,4 +35,10 @@ void Curl_amiga_cleanup();
#endif
+#ifdef USE_AMISSL
+#include <openssl/x509v3.h>
+void Curl_amiga_X509_free(X509 *a);
+#endif /* USE_AMISSL */
+
#endif /* HEADER_CURL_AMIGAOS_H */
+
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 5cfb2602d..8561a4724 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -68,7 +68,7 @@
#include "progress.h"
# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+ (defined(WIN32) || defined(__SYMBIAN32__))
# define CARES_STATICLIB
# endif
# include <ares.h>
@@ -89,8 +89,20 @@ struct ResolverResults {
int num_pending; /* number of ares_gethostbyname() requests */
Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
int last_status;
+ struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
};
+/* How long we are willing to wait for additional parallel responses after
+ obtaining a "definitive" one.
+
+ This is intended to equal the c-ares default timeout. cURL always uses that
+ default value. Unfortunately, c-ares doesn't expose its default timeout in
+ its API, but it is officially documented as 5 seconds.
+
+ See query_completed_cb() for an explanation of how this is used.
+ */
+#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
+
/*
* Curl_resolver_global_init() - the generic low-level asynchronous name
* resolve API. Called from curl_global_init() to initialize global resolver
@@ -119,6 +131,17 @@ void Curl_resolver_global_cleanup(void)
#endif
}
+
+static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd,
+ int readable, int writable)
+{
+ struct Curl_easy *easy = data;
+ if(!readable && !writable) {
+ DEBUGASSERT(easy);
+ Curl_multi_closed(easy, socket_fd);
+ }
+}
+
/*
* Curl_resolver_init()
*
@@ -126,9 +149,14 @@ void Curl_resolver_global_cleanup(void)
* URL-state specific environment ('resolver' member of the UrlState
* structure). Fills the passed pointer by the initialized ares_channel.
*/
-CURLcode Curl_resolver_init(void **resolver)
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
- int status = ares_init((ares_channel*)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_data = easy;
+ status = ares_init_options((ares_channel*)resolver, &options, optmask);
if(status != ARES_SUCCESS) {
if(status == ARES_ENOMEM)
return CURLE_OUT_OF_MEMORY;
@@ -159,12 +187,15 @@ void Curl_resolver_cleanup(void *resolver)
* environment ('resolver' member of the UrlState structure). Duplicates the
* 'from' ares channel and passes the resulting channel to the 'to' pointer.
*/
-int Curl_resolver_duphandle(void **to, void *from)
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
{
- /* Clone the ares channel for the new handle */
- if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from))
- return CURLE_FAILED_INIT;
- return CURLE_OK;
+ (void)from;
+ /*
+ * it would be better to call ares_dup instead, but right now
+ * it is not possible to set 'sock_state_cb_data' outside of
+ * ares_init_options
+ */
+ return Curl_resolver_init(easy, to);
}
static void destroy_async_data(struct Curl_async *async);
@@ -180,6 +211,17 @@ void Curl_resolver_cancel(struct connectdata *conn)
}
/*
+ * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We
+ * never block.
+ */
+void Curl_resolver_kill(struct connectdata *conn)
+{
+ /* 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);
+}
+
+/*
* destroy_async_data() cleans up async resolver data.
*/
static void destroy_async_data(struct Curl_async *async)
@@ -289,9 +331,9 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
/* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++)
ares_process_fd((ares_channel)data->state.resolver,
- pfd[i].revents & (POLLRDNORM|POLLIN)?
+ (pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD,
- pfd[i].revents & (POLLWRNORM|POLLOUT)?
+ (pfd[i].revents & (POLLWRNORM|POLLOUT))?
pfd[i].fd:ARES_SOCKET_BAD);
}
return nfds;
@@ -317,6 +359,29 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
waitperform(conn, 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
+ expires. */
+ if(res
+ && res->num_pending
+ /* This is only set to non-zero if the timer was started. */
+ && (res->happy_eyeballs_dns_time.tv_sec
+ || res->happy_eyeballs_dns_time.tv_usec)
+ && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
+ >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
+ /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
+ running. */
+ memset(
+ &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
+
+ /* Cancel the raw c-ares request, which will fire query_completed_cb() with
+ 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);
+ DEBUGASSERT(res->num_pending == 0);
+ }
+
if(res && !res->num_pending) {
if(dns) {
(void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
@@ -342,13 +407,13 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
/*
* Curl_resolver_wait_resolv()
*
- * waits for a resolve to finish. This function should be avoided since using
+ * Waits for a resolve to finish. This function should be avoided since using
* this risk getting the multi interface to "hang".
*
* If 'entry' is non-NULL, make it point to the resolved dns entry
*
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ * 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,
struct Curl_dns_entry **entry)
@@ -425,9 +490,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
if(result)
/* close the connection, since we can't return failure here without
- cleaning up this connection properly.
- TODO: remove this action from here, it is not a name resolver decision.
- */
+ cleaning up this connection properly. */
connclose(conn, "c-ares resolve failed");
return result;
@@ -487,6 +550,66 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
/* A successful result overwrites any previous error */
if(res->last_status != ARES_SUCCESS)
res->last_status = status;
+
+ /* If there are responses still pending, we presume they must be the
+ complementary IPv4 or IPv6 lookups that we started in parallel in
+ Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a
+ "definitive" response from one of a set of parallel queries, we need to
+ think about how long we're willing to wait for more responses. */
+ if(res->num_pending
+ /* Only these c-ares status values count as "definitive" for these
+ purposes. For example, ARES_ENODATA is what we expect when there is
+ no IPv6 entry for a domain name, and that's not a reason to get more
+ aggressive in our timeouts for the other response. Other errors are
+ either a result of bad input (which should affect all parallel
+ requests), local or network conditions, non-definitive server
+ responses, or us cancelling the request. */
+ && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
+ /* Right now, there can only be up to two parallel queries, so don't
+ bother handling any other cases. */
+ DEBUGASSERT(res->num_pending == 1);
+
+ /* It's possible that one of these parallel queries could succeed
+ quickly, but the other could always fail or timeout (when we're
+ talking to a pool of DNS servers that can only successfully resolve
+ IPv4 address, for example).
+
+ It's also possible that the other request could always just take
+ longer because it needs more time or only the second DNS server can
+ fulfill it successfully. But, to align with the philosophy of Happy
+ Eyeballs, we don't want to wait _too_ long or users will think
+ requests are slow when IPv6 lookups don't actually work (but IPv4 ones
+ do).
+
+ So, now that we have a usable answer (some IPv4 addresses, some IPv6
+ addresses, or "no such domain"), we start a timeout for the remaining
+ pending responses. Even though it is typical that this resolved
+ request came back quickly, that needn't be the case. It might be that
+ this completing request didn't get a result from the first DNS server
+ or even the first round of the whole DNS server pool. So it could
+ already be quite some time after we issued the DNS queries in the
+ first place. Without modifying c-ares, we can't know exactly where in
+ its retry cycle we are. We could guess based on how much time has
+ gone by, but it doesn't really matter. Happy Eyeballs tells us that,
+ given usable information in hand, we simply don't want to wait "too
+ much longer" after we get a result.
+
+ We simply wait an additional amount of time equal to the default
+ c-ares query timeout. That is enough time for a typical parallel
+ response to arrive without being "too long". Even on a network
+ where one of the two types of queries is failing or timing out
+ constantly, this will usually mean we wait a total of the default
+ c-ares timeout (5 seconds) plus the round trip time for the successful
+ request, which seems bearable. The downside is that c-ares might race
+ with us to issue one more retry just before we give up, but it seems
+ better to "waste" that request instead of trying to guess the perfect
+ timeout to prevent it. After all, we don't even know where in the
+ 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);
+ }
}
}
diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
index 2a59294e5..55e0811c5 100644
--- a/Utilities/cmcurl/lib/asyn-thread.c
+++ b/Utilities/cmcurl/lib/asyn-thread.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -108,8 +108,9 @@ void Curl_resolver_global_cleanup(void)
* URL-state specific environment ('resolver' member of the UrlState
* structure).
*/
-CURLcode Curl_resolver_init(void **resolver)
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
+ (void)easy;
*resolver = calloc(1, sizeof(struct resdata));
if(!*resolver)
return CURLE_OUT_OF_MEMORY;
@@ -132,10 +133,10 @@ void Curl_resolver_cleanup(void *resolver)
* Called from curl_easy_duphandle() to duplicate resolver URL state-specific
* environment ('resolver' member of the UrlState structure).
*/
-int Curl_resolver_duphandle(void **to, void *from)
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
{
(void)from;
- return Curl_resolver_init(to);
+ return Curl_resolver_init(easy, to);
}
static void destroy_async_data(struct Curl_async *);
@@ -276,7 +277,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
char service[12];
int rc;
- snprintf(service, sizeof(service), "%d", tsd->port);
+ msnprintf(service, sizeof(service), "%d", tsd->port);
rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
@@ -460,23 +461,15 @@ static CURLcode resolver_error(struct connectdata *conn)
return result;
}
-/*
- * Curl_resolver_wait_resolv()
- *
- * waits for a resolve to finish. This function should be avoided since using
- * this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * This is the version for resolves-in-a-thread.
- */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
- struct Curl_dns_entry **entry)
+static CURLcode thread_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry,
+ bool report)
{
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
CURLcode result = CURLE_OK;
DEBUGASSERT(conn && td);
+ DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
/* wait for the thread to resolve the name */
if(Curl_thread_join(&td->thread_hnd)) {
@@ -491,18 +484,55 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
if(entry)
*entry = conn->async.dns;
- if(!conn->async.dns)
+ if(!conn->async.dns && report)
/* a name was not resolved, report error */
result = resolver_error(conn);
destroy_async_data(&conn->async);
- if(!conn->async.dns)
+ if(!conn->async.dns && report)
connclose(conn, "asynch resolve failed");
return result;
}
+
+/*
+ * 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)
+{
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+
+ /* 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);
+ else
+ Curl_resolver_cancel(conn);
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * Waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ return thread_wait_resolv(conn, entry, TRUE);
+}
+
/*
* Curl_resolver_is_resolved() is called repeatedly to check if a previous
* name resolve request has completed. It should also make sure to time-out if
@@ -678,7 +708,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
hints.ai_family = pf;
hints.ai_socktype = conn->socktype;
- snprintf(sbuf, sizeof(sbuf), "%d", port);
+ msnprintf(sbuf, sizeof(sbuf), "%d", port);
reslv->start = Curl_now();
/* fire up a new resolver thread! */
diff --git a/Utilities/cmcurl/lib/asyn.h b/Utilities/cmcurl/lib/asyn.h
index 3adc3664a..ccd4b1f7e 100644
--- a/Utilities/cmcurl/lib/asyn.h
+++ b/Utilities/cmcurl/lib/asyn.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -60,7 +60,7 @@ void Curl_resolver_global_cleanup(void);
* Returning anything else than CURLE_OK fails curl_easy_init() with the
* correspondent code.
*/
-CURLcode Curl_resolver_init(void **resolver);
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);
/*
* Curl_resolver_cleanup()
@@ -79,17 +79,33 @@ void Curl_resolver_cleanup(void *resolver);
* pointer. Returning anything else than CURLE_OK causes failed
* curl_easy_duphandle() call.
*/
-int Curl_resolver_duphandle(void **to, void *from);
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
+ void *from);
/*
* Curl_resolver_cancel().
*
* It is called from inside other functions to cancel currently performing
* resolver request. Should also free any temporary resources allocated to
- * perform a request.
+ * perform a request. This never waits for resolver threads to complete.
+ *
+ * It is safe to call this when conn is in any state.
*/
void Curl_resolver_cancel(struct connectdata *conn);
+/*
+ * Curl_resolver_kill().
+ *
+ * This acts like Curl_resolver_cancel() except it will block until any threads
+ * associated with the resolver are complete. This never blocks for resolvers
+ * that do not use threads. This is intended to be the "last chance" function
+ * that cleans up an in-progress resolver completely (before its owner is about
+ * to die).
+ *
+ * It is safe to call this when conn is in any state.
+ */
+void Curl_resolver_kill(struct connectdata *conn);
+
/* Curl_resolver_getsock()
*
* This function is called from the multi_getsock() function. 'sock' is a
@@ -116,14 +132,13 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
/*
* Curl_resolver_wait_resolv()
*
- * waits for a resolve to finish. This function should be avoided since using
+ * Waits for a resolve to finish. This function should be avoided since using
* this risk getting the multi interface to "hang".
*
* If 'entry' is non-NULL, make it point to the resolved dns entry
*
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
-
+ * 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,
struct Curl_dns_entry **dnsentry);
@@ -147,11 +162,12 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
#ifndef CURLRES_ASYNCH
/* convert these functions if an asynch resolver isn't used */
#define Curl_resolver_cancel(x) Curl_nop_stmt
+#define Curl_resolver_kill(x) Curl_nop_stmt
#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_getsock(x,y,z) 0
-#define Curl_resolver_duphandle(x,y) CURLE_OK
-#define Curl_resolver_init(x) CURLE_OK
+#define Curl_resolver_duphandle(x,y,z) CURLE_OK
+#define Curl_resolver_init(x,y) CURLE_OK
#define Curl_resolver_global_init() CURLE_OK
#define Curl_resolver_global_cleanup() Curl_nop_stmt
#define Curl_resolver_cleanup(x) Curl_nop_stmt
diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c
index 6370e4cdf..fb081a6bb 100644
--- a/Utilities/cmcurl/lib/base64.c
+++ b/Utilities/cmcurl/lib/base64.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -23,6 +23,11 @@
/* Base64 encoding/decoding */
#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_LIBSSH2) || \
+ defined(USE_LIBSSH) || !defined(CURL_DISABLE_LDAP) || \
+ !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
+
#include "urldata.h" /* for the Curl_easy definition */
#include "warnless.h"
#include "curl_base64.h"
@@ -233,24 +238,24 @@ static CURLcode base64_encode(const char *table64,
switch(inputparts) {
case 1: /* only one byte read */
- snprintf(output, 5, "%c%c==",
- table64[obuf[0]],
- table64[obuf[1]]);
+ msnprintf(output, 5, "%c%c==",
+ table64[obuf[0]],
+ table64[obuf[1]]);
break;
case 2: /* two bytes read */
- snprintf(output, 5, "%c%c%c=",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]]);
+ msnprintf(output, 5, "%c%c%c=",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]]);
break;
default:
- snprintf(output, 5, "%c%c%c%c",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]],
- table64[obuf[3]]);
+ msnprintf(output, 5, "%c%c%c%c",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]],
+ table64[obuf[3]]);
break;
}
output += 4;
@@ -317,3 +322,5 @@ CURLcode Curl_base64url_encode(struct Curl_easy *data,
{
return base64_encode(base64url, data, inputbuff, insize, outptr, outlen);
}
+
+#endif /* no users so disabled */
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index 6fbf3b1d2..535091996 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -175,12 +175,12 @@ static void hashkey(struct connectdata *conn, char *buf,
DEBUGASSERT(len > 32);
/* put the number first so that the hostname gets cut off if too long */
- snprintf(buf, len, "%ld%s", conn->port, hostname);
+ msnprintf(buf, len, "%ld%s", conn->port, hostname);
}
-void Curl_conncache_unlock(struct connectdata *conn)
+void Curl_conncache_unlock(struct Curl_easy *data)
{
- CONN_UNLOCK(conn->data);
+ CONN_UNLOCK(data);
}
/* Returns number of connections currently held in the connection cache.
@@ -302,9 +302,14 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
return result;
}
-void Curl_conncache_remove_conn(struct connectdata *conn, bool lock)
+/*
+ * Removes the connectdata object from the connection cache *and* clears the
+ * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument
+ * depending on if the parent function already holds the lock or not.
+ */
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+ struct connectdata *conn, bool lock)
{
- struct Curl_easy *data = conn->data;
struct connectbundle *bundle = conn->bundle;
struct conncache *connc = data->state.conn_cache;
@@ -323,6 +328,7 @@ void Curl_conncache_remove_conn(struct connectdata *conn, bool lock)
DEBUGF(infof(data, "The cache now contains %zu members\n",
connc->num_conn));
}
+ conn->data = NULL; /* clear the association */
if(lock) {
CONN_UNLOCK(data);
}
@@ -386,8 +392,8 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
NOTE: no locking is done here as this is presumably only done when cleaning
up a cache!
*/
-struct connectdata *
-Curl_conncache_find_first_connection(struct conncache *connc)
+static struct connectdata *
+conncache_find_first_connection(struct conncache *connc)
{
struct curl_hash_iterator iter;
struct curl_hash_element *he;
@@ -427,6 +433,8 @@ bool Curl_conncache_return_conn(struct connectdata *conn)
data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
+ conn->data = NULL; /* no owner anymore */
+ conn->lastused = Curl_now(); /* it was used up until now */
if(maxconnects > 0 &&
Curl_conncache_size(data) > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n");
@@ -470,9 +478,9 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
while(curr) {
conn = curr->ptr;
- if(!CONN_INUSE(conn)) {
+ if(!CONN_INUSE(conn) && !conn->data) {
/* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->now);
+ score = Curl_timediff(now, conn->lastused);
if(score > highscore) {
highscore = score;
@@ -528,9 +536,9 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
while(curr) {
conn = curr->ptr;
- if(!CONN_INUSE(conn)) {
+ if(!CONN_INUSE(conn) && !conn->data) {
/* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->now);
+ score = Curl_timediff(now, conn->lastused);
if(score > highscore) {
highscore = score;
@@ -560,20 +568,18 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
{
struct connectdata *conn;
- conn = Curl_conncache_find_first_connection(connc);
+ conn = conncache_find_first_connection(connc);
while(conn) {
SIGPIPE_VARIABLE(pipe_st);
conn->data = connc->closure_handle;
sigpipe_ignore(conn->data, &pipe_st);
- conn->data->easy_conn = NULL; /* clear the easy handle's connection
- pointer */
/* This will remove the connection from the cache */
connclose(conn, "kill all");
(void)Curl_disconnect(connc->closure_handle, conn, FALSE);
sigpipe_restore(&pipe_st);
- conn = Curl_conncache_find_first_connection(connc);
+ conn = conncache_find_first_connection(connc);
}
if(connc->closure_handle) {
diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h
index eedd7a800..35be9e0aa 100644
--- a/Utilities/cmcurl/lib/conncache.h
+++ b/Utilities/cmcurl/lib/conncache.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2015 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2019, 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
@@ -40,7 +40,6 @@ struct conncache {
#define BUNDLE_NO_MULTIUSE -1
#define BUNDLE_UNKNOWN 0 /* initial value */
-#define BUNDLE_PIPELINING 1
#define BUNDLE_MULTIPLEX 2
struct connectbundle {
@@ -56,7 +55,7 @@ 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 conncache *connc);
-void Curl_conncache_unlock(struct connectdata *conn);
+void Curl_conncache_unlock(struct Curl_easy *data);
/* returns number of connections currently held in the connection cache */
size_t Curl_conncache_size(struct Curl_easy *data);
size_t Curl_conncache_bundle_size(struct connectdata *conn);
@@ -64,7 +63,8 @@ size_t Curl_conncache_bundle_size(struct connectdata *conn);
bool Curl_conncache_return_conn(struct connectdata *conn);
CURLcode Curl_conncache_add_conn(struct conncache *connc,
struct connectdata *conn) WARN_UNUSED_RESULT;
-void Curl_conncache_remove_conn(struct connectdata *conn,
+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,
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index 41f220268..002535b42 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -357,7 +357,7 @@ static CURLcode bindlocal(struct connectdata *conn,
conn->ip_version = CURL_IPRESOLVE_V6;
#endif
- rc = Curl_resolv(conn, dev, 0, &h);
+ rc = Curl_resolv(conn, dev, 0, FALSE, &h);
if(rc == CURLRESOLV_PENDING)
(void)Curl_resolver_wait_resolv(conn, &h);
conn->ip_version = ipver;
@@ -446,9 +446,10 @@ static CURLcode bindlocal(struct connectdata *conn,
curl_socklen_t size = sizeof(add);
memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+ char buffer[STRERROR_LEN];
data->state.os_errno = error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
- error, Curl_strerror(conn, error));
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
return CURLE_INTERFACE_FAILED;
}
infof(data, "Local port: %hu\n", port);
@@ -470,10 +471,12 @@ static CURLcode bindlocal(struct connectdata *conn,
else
break;
}
-
- data->state.os_errno = error = SOCKERRNO;
- failf(data, "bind failed with errno %d: %s",
- error, Curl_strerror(conn, error));
+ {
+ char buffer[STRERROR_LEN];
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "bind failed with errno %d: %s",
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
+ }
return CURLE_INTERFACE_FAILED;
}
@@ -522,7 +525,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
err = 0;
}
#endif
-#ifdef __minix
+#if defined(EBADIOCTL) && defined(__minix)
/* Minix 3.1.x doesn't support getsockopt on UDP sockets */
if(EBADIOCTL == err) {
SET_SOCKERRNO(0);
@@ -617,12 +620,14 @@ void Curl_persistconninfo(struct connectdata *conn)
conn->data->info.conn_local_port = conn->local_port;
}
+UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
+ long *port);
+
/* retrieves ip address and port from a sockaddr structure.
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
-bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
- long *port)
+UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
+ long *port)
{
- unsigned short us_port;
struct sockaddr_in *si = NULL;
#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = NULL;
@@ -636,7 +641,7 @@ bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
si = (struct sockaddr_in *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
addr, MAX_IPADR_LEN)) {
- us_port = ntohs(si->sin_port);
+ unsigned short us_port = ntohs(si->sin_port);
*port = us_port;
return TRUE;
}
@@ -646,7 +651,7 @@ bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
addr, MAX_IPADR_LEN)) {
- us_port = ntohs(si6->sin6_port);
+ unsigned short us_port = ntohs(si6->sin6_port);
*port = us_port;
return TRUE;
}
@@ -655,7 +660,7 @@ bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
case AF_UNIX:
su = (struct sockaddr_un*)sa;
- snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+ msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
*port = 0;
return TRUE;
#endif
@@ -673,49 +678,57 @@ bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
connection */
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
{
- curl_socklen_t len;
- struct Curl_sockaddr_storage ssrem;
- struct Curl_sockaddr_storage ssloc;
- struct Curl_easy *data = conn->data;
-
if(conn->socktype == SOCK_DGRAM)
/* there's no connection! */
return;
+#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 len;
+#ifdef HAVE_GETPEERNAME
len = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
int error = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
- error, Curl_strerror(conn, error));
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
-
+#endif
+#ifdef HAVE_GETSOCKNAME
len = sizeof(struct Curl_sockaddr_storage);
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
int error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
- error, Curl_strerror(conn, error));
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
-
- if(!Curl_getaddressinfo((struct sockaddr*)&ssrem,
- conn->primary_ip, &conn->primary_port)) {
+#endif
+#ifdef HAVE_GETPEERNAME
+ if(!getaddressinfo((struct sockaddr*)&ssrem,
+ conn->primary_ip, &conn->primary_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
-
- if(!Curl_getaddressinfo((struct sockaddr*)&ssloc,
- conn->local_ip, &conn->local_port)) {
+#endif
+#ifdef HAVE_GETSOCKNAME
+ if(!getaddressinfo((struct sockaddr*)&ssloc,
+ conn->local_ip, &conn->local_port)) {
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
-
+#endif
}
+#else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */
+ (void)sockfd; /* unused */
+#endif
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@@ -836,9 +849,11 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(conn->tempaddr[i]) {
CURLcode status;
char ipaddress[MAX_IPADR_LEN];
+ char buffer[STRERROR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
infof(data, "connect to %s port %ld failed: %s\n",
- ipaddress, conn->port, Curl_strerror(conn, error));
+ ipaddress, conn->port,
+ Curl_strerror(error, buffer, sizeof(buffer)));
conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
allow : allow / 2;
@@ -854,8 +869,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(result) {
/* no more addresses to try */
-
const char *hostname;
+ char buffer[STRERROR_LEN];
/* if the first address family runs out of addresses to try before
the happy eyeball timeout, go ahead and try the next family now */
@@ -875,13 +890,14 @@ CURLcode Curl_is_connected(struct connectdata *conn,
hostname = conn->host.name;
failf(data, "Failed to connect to %s port %ld: %s",
- hostname, conn->port, Curl_strerror(conn, error));
+ hostname, conn->port,
+ Curl_strerror(error, buffer, sizeof(buffer)));
}
return result;
}
-void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
+static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
{
#if defined(TCP_NODELAY)
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -889,6 +905,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
#endif
curl_socklen_t onoff = (curl_socklen_t) 1;
int level = IPPROTO_TCP;
+ char buffer[STRERROR_LEN];
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) conn;
@@ -897,7 +914,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
sizeof(onoff)) < 0)
infof(data, "Could not set TCP_NODELAY: %s\n",
- Curl_strerror(conn, SOCKERRNO));
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
else
infof(data, "TCP_NODELAY set\n");
#else
@@ -917,9 +934,11 @@ static void nosigpipe(struct connectdata *conn,
struct Curl_easy *data = conn->data;
int onoff = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
- sizeof(onoff)) < 0)
+ sizeof(onoff)) < 0) {
+ char buffer[STRERROR_LEN];
infof(data, "Could not set SO_NOSIGPIPE: %s\n",
- Curl_strerror(conn, SOCKERRNO));
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+ }
}
#else
#define nosigpipe(x,y) Curl_nop_stmt
@@ -995,6 +1014,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
#ifdef TCP_FASTOPEN_CONNECT
int optval = 1;
#endif
+ char buffer[STRERROR_LEN];
*sockp = CURL_SOCKET_BAD;
@@ -1006,15 +1026,15 @@ static CURLcode singleipconnect(struct connectdata *conn,
return CURLE_OK;
/* store remote address and port used in this connection attempt */
- if(!Curl_getaddressinfo((struct sockaddr*)&addr.sa_addr,
- ipaddress, &port)) {
+ if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
+ ipaddress, &port)) {
/* malformed address or bug in inet_ntop, try next address */
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
Curl_closesocket(conn, sockfd);
return CURLE_OK;
}
- infof(data, " Trying %s...\n", ipaddress);
+ infof(data, " Trying %s:%ld...\n", ipaddress, port);
#ifdef ENABLE_IPV6
is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
@@ -1023,7 +1043,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
#endif
if(is_tcp && data->set.tcp_nodelay)
- Curl_tcpnodelay(conn, sockfd);
+ tcpnodelay(conn, sockfd);
nosigpipe(conn, sockfd);
@@ -1146,7 +1166,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
default:
/* unknown error, fallthrough and try another address! */
infof(data, "Immediate connect fail for %s: %s\n",
- ipaddress, Curl_strerror(conn, error));
+ ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
data->state.os_errno = error;
/* connect failed */
@@ -1314,7 +1334,7 @@ int Curl_closesocket(struct connectdata *conn,
conn->sock_accepted[SECONDARYSOCKET] = FALSE;
else {
int rc;
- Curl_multi_closed(conn, sock);
+ Curl_multi_closed(conn->data, sock);
Curl_set_in_callback(conn->data, true);
rc = conn->fclosesocket(conn->closesocket_client, sock);
Curl_set_in_callback(conn->data, false);
@@ -1324,7 +1344,7 @@ int Curl_closesocket(struct connectdata *conn,
if(conn)
/* tell the multi-socket code about this */
- Curl_multi_closed(conn, sock);
+ Curl_multi_closed(conn->data, sock);
sclose(sock);
@@ -1420,7 +1440,7 @@ void Curl_conncontrol(struct connectdata *conn,
if((ctrl == CONNCTRL_STREAM) &&
(conn->handler->flags & PROTOPT_STREAM))
DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
- else if(closeit != conn->bits.close) {
+ 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
diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h
index 193dc6397..6a5c755cc 100644
--- a/Utilities/cmcurl/lib/connect.h
+++ b/Utilities/cmcurl/lib/connect.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -76,11 +76,6 @@ void Curl_persistconninfo(struct connectdata *conn);
int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
/*
- * Get presentation format IP address and port from a sockaddr.
- */
-bool Curl_getaddressinfo(struct sockaddr *sa, char *addr, long *port);
-
-/*
* The Curl_sockaddr_ex structure is basically libcurl's external API
* curl_sockaddr structure with enough space available to directly hold any
* protocol-specific address structures. The variable declared here will be
@@ -111,8 +106,6 @@ CURLcode Curl_socket(struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
curl_socket_t *sockfd);
-void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd);
-
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
* argument specifies if it is the end of a connection or a stream.
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index a342c61de..9a9e14d01 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -93,6 +93,7 @@ Example set of cookies:
#include "share.h"
#include "strtoofft.h"
#include "strcase.h"
+#include "curl_get_line.h"
#include "curl_memrchr.h"
#include "inet_pton.h"
@@ -223,7 +224,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
goto pathmatched;
}
- /* here, cookie_path_len < url_path_len */
+ /* here, cookie_path_len < uri_path_len */
if(uri_path[cookie_path_len] == '/') {
ret = TRUE;
goto pathmatched;
@@ -433,9 +434,10 @@ Curl_cookie_add(struct Curl_easy *data,
bool noexpire, /* if TRUE, skip remove_expired() */
char *lineptr, /* first character of the line */
const char *domain, /* default domain */
- const char *path) /* full path used when this cookie is set,
+ const char *path, /* full path used when this cookie is set,
used to get default path for the cookie
unless set */
+ bool secure) /* TRUE if connection is over secure origin */
{
struct Cookie *clist;
struct Cookie *co;
@@ -527,6 +529,19 @@ Curl_cookie_add(struct Curl_easy *data,
while(*whatptr && ISBLANK(*whatptr))
whatptr++;
+ /*
+ * Check if we have a reserved prefix set before anything else, as we
+ * otherwise have to test for the prefix in both the cookie name and
+ * "the rest". Prefixes must start with '__' and end with a '-', so
+ * only test for names where that can possibly be true.
+ */
+ if(nlen > 3 && name[0] == '_' && name[1] == '_') {
+ if(strncasecompare("__Secure-", name, 9))
+ co->prefix |= COOKIE_PREFIX__SECURE;
+ else if(strncasecompare("__Host-", name, 7))
+ co->prefix |= COOKIE_PREFIX__HOST;
+ }
+
if(!co->name) {
/* The very first name/value pair is the actual cookie name */
if(!sep) {
@@ -546,8 +561,20 @@ Curl_cookie_add(struct Curl_easy *data,
/* this was a "<name>=" with no content, and we must allow
'secure' and 'httponly' specified this weirdly */
done = TRUE;
- if(strcasecompare("secure", name))
- co->secure = TRUE;
+ /*
+ * secure cookies are only allowed to be set when the connection is
+ * using a secure protocol, or when the cookie is being set by
+ * reading from file
+ */
+ if(strcasecompare("secure", name)) {
+ if(secure || !c->running) {
+ co->secure = TRUE;
+ }
+ else {
+ badcookie = TRUE;
+ break;
+ }
+ }
else if(strcasecompare("httponly", name))
co->httponly = TRUE;
else if(sep)
@@ -675,7 +702,10 @@ Curl_cookie_add(struct Curl_easy *data,
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
else if(!offt) {
- if(CURL_OFF_T_MAX - now < co->expires)
+ if(!co->expires)
+ /* already expired */
+ co->expires = 1;
+ else if(CURL_OFF_T_MAX - now < co->expires)
/* would overflow */
co->expires = CURL_OFF_T_MAX;
else
@@ -828,7 +858,13 @@ Curl_cookie_add(struct Curl_easy *data,
fields++; /* add a field and fall down to secure */
/* FALLTHROUGH */
case 3:
- co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
+ co->secure = FALSE;
+ if(strcasecompare(ptr, "TRUE")) {
+ if(secure || c->running)
+ co->secure = TRUE;
+ else
+ badcookie = TRUE;
+ }
break;
case 4:
if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
@@ -838,6 +874,13 @@ Curl_cookie_add(struct Curl_easy *data,
co->name = strdup(ptr);
if(!co->name)
badcookie = TRUE;
+ else {
+ /* For Netscape file format cookies we check prefix on the name */
+ if(strncasecompare("__Secure-", co->name, 9))
+ co->prefix |= COOKIE_PREFIX__SECURE;
+ else if(strncasecompare("__Host-", co->name, 7))
+ co->prefix |= COOKIE_PREFIX__HOST;
+ }
break;
case 6:
co->value = strdup(ptr);
@@ -866,6 +909,26 @@ Curl_cookie_add(struct Curl_easy *data,
}
+ if(co->prefix & COOKIE_PREFIX__SECURE) {
+ /* The __Secure- prefix only requires that the cookie be set secure */
+ if(!co->secure) {
+ freecookie(co);
+ return NULL;
+ }
+ }
+ if(co->prefix & COOKIE_PREFIX__HOST) {
+ /*
+ * The __Host- prefix requires the cookie to be secure, have a "/" path
+ * and not have a domain set.
+ */
+ if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
+ ;
+ else {
+ freecookie(co);
+ return NULL;
+ }
+ }
+
if(!c->running && /* read from a file */
c->newsession && /* clean session cookies */
!co->expires) { /* this is a session cookie since it doesn't expire! */
@@ -926,9 +989,31 @@ Curl_cookie_add(struct Curl_easy *data,
/* the domains were identical */
if(clist->spath && co->spath) {
- if(strcasecompare(clist->spath, co->spath)) {
- replace_old = TRUE;
+ if(clist->secure && !co->secure && !secure) {
+ size_t cllen;
+ const char *sep;
+
+ /*
+ * A non-secure cookie may not overlay an existing secure cookie.
+ * For an existing cookie "a" with path "/login", refuse a new
+ * cookie "a" with for example path "/login/en", while the path
+ * "/loginhelper" is ok.
+ */
+
+ sep = strchr(clist->spath + 1, '/');
+
+ if(sep)
+ cllen = sep - clist->spath;
+ else
+ cllen = strlen(clist->spath);
+
+ if(strncasecompare(clist->spath, co->spath, cllen)) {
+ freecookie(co);
+ return NULL;
+ }
}
+ else if(strcasecompare(clist->spath, co->spath))
+ replace_old = TRUE;
else
replace_old = FALSE;
}
@@ -1003,33 +1088,6 @@ Curl_cookie_add(struct Curl_easy *data,
return co;
}
-/*
- * get_line() makes sure to only return complete whole lines that fit in 'len'
- * bytes and end with a newline.
- */
-static char *get_line(char *buf, int len, FILE *input)
-{
- bool partial = FALSE;
- while(1) {
- char *b = fgets(buf, len, input);
- if(b) {
- size_t rlen = strlen(b);
- if(rlen && (b[rlen-1] == '\n')) {
- if(partial) {
- partial = FALSE;
- continue;
- }
- return b;
- }
- /* read a partial, discard the next piece that ends with newline */
- partial = TRUE;
- }
- else
- break;
- }
- return NULL;
-}
-
/*****************************************************************************
*
@@ -1087,7 +1145,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
line = malloc(MAX_COOKIE_LINE);
if(!line)
goto fail;
- while(get_line(line, MAX_COOKIE_LINE, fp)) {
+ while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
if(checkprefix("Set-Cookie:", line)) {
/* This is a cookie line, get it! */
lineptr = &line[11];
@@ -1100,7 +1158,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
- Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL);
+ Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
}
free(line); /* free the line buffer */
remove_expired(c); /* run this once, not on every cookie */
@@ -1451,27 +1509,14 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
struct Cookie *co;
FILE *out;
bool use_stdout = FALSE;
- char *format_ptr;
- unsigned int i;
- unsigned int j;
- struct Cookie **array;
- if((NULL == c) || (0 == c->numcookies))
- /* If there are no known cookies, we don't write or even create any
- destination file */
+ if(!c)
+ /* no cookie engine alive */
return 0;
/* at first, remove expired cookies */
remove_expired(c);
- /* make sure we still have cookies after expiration */
- if(0 == c->numcookies)
- return 0;
-
- array = malloc(sizeof(struct Cookie *) * c->numcookies);
- if(!array)
- return 1;
-
if(!strcmp("-", dumphere)) {
/* use stdout */
out = stdout;
@@ -1480,7 +1525,6 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
else {
out = fopen(dumphere, FOPEN_WRITETEXT);
if(!out) {
- free(array);
return 1; /* failure */
}
}
@@ -1490,32 +1534,44 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
"# This file was generated by libcurl! Edit at your own risk.\n\n",
out);
- j = 0;
- for(i = 0; i < COOKIE_HASH_SIZE; i++) {
- for(co = c->cookies[i]; co; co = co->next) {
- if(!co->domain)
- continue;
- array[j++] = co;
- }
- }
-
- qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct);
+ if(c->numcookies) {
+ unsigned int i;
+ unsigned int j;
+ struct Cookie **array;
- for(i = 0; i < j; i++) {
- format_ptr = get_netscape_format(array[i]);
- if(format_ptr == NULL) {
- fprintf(out, "#\n# Fatal libcurl error\n");
- free(array);
+ array = malloc(sizeof(struct Cookie *) * c->numcookies);
+ if(!array) {
if(!use_stdout)
fclose(out);
return 1;
}
- fprintf(out, "%s\n", format_ptr);
- free(format_ptr);
- }
- free(array);
+ j = 0;
+ for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+ for(co = c->cookies[i]; co; co = co->next) {
+ if(!co->domain)
+ continue;
+ array[j++] = co;
+ }
+ }
+
+ qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct);
+ for(i = 0; i < j; i++) {
+ char *format_ptr = get_netscape_format(array[i]);
+ if(format_ptr == NULL) {
+ fprintf(out, "#\n# Fatal libcurl error\n");
+ free(array);
+ if(!use_stdout)
+ fclose(out);
+ return 1;
+ }
+ fprintf(out, "%s\n", format_ptr);
+ free(format_ptr);
+ }
+
+ free(array);
+ }
if(!use_stdout)
fclose(out);
diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h
index a9f90ca71..b2730cfb9 100644
--- a/Utilities/cmcurl/lib/cookie.h
+++ b/Utilities/cmcurl/lib/cookie.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -44,8 +44,16 @@ struct Cookie {
bool livecookie; /* updated from a server, not a stored file */
bool httponly; /* true if the httponly directive is present */
int creationtime; /* time when the cookie was written */
+ unsigned char prefix; /* bitmap fields indicating which prefix are set */
};
+/*
+ * Available cookie prefixes, as defined in
+ * draft-ietf-httpbis-rfc6265bis-02
+ */
+#define COOKIE_PREFIX__SECURE (1<<0)
+#define COOKIE_PREFIX__HOST (1<<1)
+
#define COOKIE_HASH_SIZE 256
struct CookieInfo {
@@ -85,7 +93,8 @@ struct Curl_easy;
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
struct CookieInfo *, bool header, bool noexpiry,
char *lineptr,
- const char *domain, const char *path);
+ const char *domain, const char *path,
+ bool secure);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
const char *, bool);
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c
index fd49679c9..16c4779c1 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.c
+++ b/Utilities/cmcurl/lib/curl_addrinfo.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -539,7 +539,7 @@ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
defined(HAVE_FREEADDRINFO)
/*
- * curl_dofreeaddrinfo()
+ * curl_dbg_freeaddrinfo()
*
* This is strictly for memory tracing and are using the same style as the
* family otherwise present in memdebug.c. I put these ones here since they
@@ -547,23 +547,23 @@ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
*/
void
-curl_dofreeaddrinfo(struct addrinfo *freethis,
- int line, const char *source)
+curl_dbg_freeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source)
{
+ curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
+ source, line, (void *)freethis);
#ifdef USE_LWIPSOCK
lwip_freeaddrinfo(freethis);
#else
(freeaddrinfo)(freethis);
#endif
- curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
- source, line, (void *)freethis);
}
#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
/*
- * curl_dogetaddrinfo()
+ * curl_dbg_getaddrinfo()
*
* This is strictly for memory tracing and are using the same style as the
* family otherwise present in memdebug.c. I put these ones here since they
@@ -571,11 +571,11 @@ curl_dofreeaddrinfo(struct addrinfo *freethis,
*/
int
-curl_dogetaddrinfo(const char *hostname,
- const char *service,
- const struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source)
+curl_dbg_getaddrinfo(const char *hostname,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source)
{
#ifdef USE_LWIPSOCK
int res = lwip_getaddrinfo(hostname, service, hints, result);
@@ -584,11 +584,11 @@ curl_dogetaddrinfo(const char *hostname,
#endif
if(0 == res)
/* success */
- curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
- source, line, (void *)*result);
+ curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n",
+ source, line, (void *)*result);
else
- curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
- source, line);
+ curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n",
+ source, line);
return res;
}
#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h
index 8f6f3d106..205e121ea 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.h
+++ b/Utilities/cmcurl/lib/curl_addrinfo.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -86,17 +86,14 @@ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract);
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
defined(HAVE_FREEADDRINFO)
void
-curl_dofreeaddrinfo(struct addrinfo *freethis,
- int line, const char *source);
+curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source);
#endif
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
int
-curl_dogetaddrinfo(const char *hostname,
- const char *service,
- const struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source);
+curl_dbg_getaddrinfo(const char *hostname, const char *service,
+ const struct addrinfo *hints, struct addrinfo **result,
+ int line, const char *source);
#endif
#ifdef HAVE_GETADDRINFO
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index d5e3a90cf..b285c3fdd 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -226,6 +226,12 @@
/* Define to 1 if you have the `getprotobyname' function. */
#cmakedefine HAVE_GETPROTOBYNAME 1
+/* Define to 1 if you have the `getpeername' function. */
+#cmakedefine HAVE_GETPEERNAME 1
+
+/* Define to 1 if you have the `getsockname' function. */
+#cmakedefine HAVE_GETSOCKNAME 1
+
/* Define to 1 if you have the `getpwuid' function. */
#cmakedefine HAVE_GETPWUID 1
@@ -930,8 +936,8 @@
/* if PolarSSL is enabled */
#cmakedefine USE_POLARSSL 1
-/* if DarwinSSL is enabled */
-#cmakedefine USE_DARWINSSL 1
+/* if Secure Transport is enabled */
+#cmakedefine USE_SECTRANSP 1
/* if mbedTLS is enabled */
#cmakedefine USE_MBEDTLS 1
diff --git a/Utilities/cmcurl/lib/curl_endian.c b/Utilities/cmcurl/lib/curl_endian.c
index c25db4956..b7563b3de 100644
--- a/Utilities/cmcurl/lib/curl_endian.c
+++ b/Utilities/cmcurl/lib/curl_endian.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -82,7 +82,7 @@ unsigned short Curl_read16_be(const unsigned char *buf)
}
/*
- * Curl_write32_le()
+ * write32_le()
*
* This function converts a 32-bit integer from the native endian format,
* to little endian format ready for sending down the wire.
@@ -92,7 +92,7 @@ unsigned short Curl_read16_be(const unsigned char *buf)
* value [in] - The 32-bit integer value.
* buffer [in] - A pointer to the output buffer.
*/
-void Curl_write32_le(const int value, unsigned char *buffer)
+static void write32_le(const int value, unsigned char *buffer)
{
buffer[0] = (char)(value & 0x000000FF);
buffer[1] = (char)((value & 0x0000FF00) >> 8);
@@ -118,7 +118,7 @@ void Curl_write64_le(const long long value, unsigned char *buffer)
void Curl_write64_le(const __int64 value, unsigned char *buffer)
#endif
{
- Curl_write32_le((int)value, buffer);
- Curl_write32_le((int)(value >> 32), buffer + 4);
+ write32_le((int)value, buffer);
+ write32_le((int)(value >> 32), buffer + 4);
}
#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */
diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c
index fbfd85c43..ab3e7428d 100644
--- a/Utilities/cmcurl/lib/curl_fnmatch.c
+++ b/Utilities/cmcurl/lib/curl_fnmatch.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -21,7 +21,7 @@
***************************************************************************/
#include "curl_setup.h"
-
+#ifndef CURL_DISABLE_FTP
#include <curl/curl.h>
#include "curl_fnmatch.h"
@@ -32,15 +32,6 @@
#ifndef HAVE_FNMATCH
-/*
- * TODO:
- *
- * Make this function match POSIX. Test 1307 includes a set of test patterns
- * that returns different results with a POSIX fnmatch() than with this
- * implementation and this is considered a bug where POSIX is the guiding
- * light.
- */
-
#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
@@ -394,3 +385,5 @@ int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
}
#endif
+
+#endif /* if FTP is disabled */
diff --git a/Utilities/cmcurl/lib/curl_get_line.c b/Utilities/cmcurl/lib/curl_get_line.c
new file mode 100644
index 000000000..c4194851a
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_get_line.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2019, 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"
+
+#include "curl_get_line.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * get_line() makes sure to only return complete whole lines that fit in 'len'
+ * bytes and end with a newline.
+ */
+char *Curl_get_line(char *buf, int len, FILE *input)
+{
+ bool partial = FALSE;
+ while(1) {
+ char *b = fgets(buf, len, input);
+ if(b) {
+ size_t rlen = strlen(b);
+ if(rlen && (b[rlen-1] == '\n')) {
+ if(partial) {
+ partial = FALSE;
+ continue;
+ }
+ return b;
+ }
+ /* read a partial, discard the next piece that ends with newline */
+ partial = TRUE;
+ }
+ else
+ break;
+ }
+ return NULL;
+}
diff --git a/Utilities/cmcurl/lib/vtls/axtls.h b/Utilities/cmcurl/lib/curl_get_line.h
index cb8187272..532ab080a 100644
--- a/Utilities/cmcurl/lib/vtls/axtls.h
+++ b/Utilities/cmcurl/lib/curl_get_line.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_AXTLS_H
-#define HEADER_CURL_AXTLS_H
+#ifndef HEADER_CURL_GET_LINE_H
+#define HEADER_CURL_GET_LINE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,8 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com>
- * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -23,11 +22,8 @@
*
***************************************************************************/
-#ifdef USE_AXTLS
-#include "curl/curl.h"
-#include "urldata.h"
+/* get_line() makes sure to only return complete whole lines that fit in 'len'
+ * bytes and end with a newline. */
+char *Curl_get_line(char *buf, int len, FILE *input);
-extern const struct Curl_ssl Curl_ssl_axtls;
-
-#endif /* USE_AXTLS */
-#endif /* HEADER_CURL_AXTLS_H */
+#endif /* HEADER_CURL_GET_LINE_H */
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index f007986c0..d854ab0c7 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -97,9 +97,9 @@ static size_t display_gss_error(OM_uint32 status, int type,
&msg_ctx,
&status_string);
if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) {
- len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
- "%.*s. ", (int)status_string.length,
- (char *)status_string.value);
+ len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
+ "%.*s. ", (int)status_string.length,
+ (char *)status_string.value);
}
gss_release_buffer(&min_stat, &status_string);
} while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
diff --git a/Utilities/cmcurl/lib/curl_gssapi.h b/Utilities/cmcurl/lib/curl_gssapi.h
index 9700a2817..88f68dbbb 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.h
+++ b/Utilities/cmcurl/lib/curl_gssapi.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2019, 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
@@ -26,19 +26,6 @@
#include "urldata.h"
#ifdef HAVE_GSSAPI
-
-#ifdef HAVE_GSSGNU
-# include <gss.h>
-#elif defined HAVE_GSSMIT
- /* MIT style */
-# include <gssapi/gssapi.h>
-# include <gssapi/gssapi_generic.h>
-# include <gssapi/gssapi_krb5.h>
-#else
- /* Heimdal-style */
-# include <gssapi.h>
-#endif
-
extern gss_OID_desc Curl_spnego_mech_oid;
extern gss_OID_desc Curl_krb5_mech_oid;
@@ -71,5 +58,4 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
#define GSSAUTH_P_PRIVACY 4
#endif /* HAVE_GSSAPI */
-
#endif /* HEADER_CURL_GSSAPI_H */
diff --git a/Utilities/cmcurl/lib/curl_md4.h b/Utilities/cmcurl/lib/curl_md4.h
index e0690416d..392203f9e 100644
--- a/Utilities/cmcurl/lib/curl_md4.h
+++ b/Utilities/cmcurl/lib/curl_md4.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -25,11 +25,13 @@
#include "curl_setup.h"
#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
+ (defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) || \
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len);
#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) ||
+ (defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) ||
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */
#endif /* HEADER_CURL_MD4_H */
diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h
index 5f70c9634..aaf25f61b 100644
--- a/Utilities/cmcurl/lib/curl_md5.h
+++ b/Utilities/cmcurl/lib/curl_md5.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -53,10 +53,10 @@ void Curl_md5it(unsigned char *output,
const unsigned char *input);
MD5_context * Curl_MD5_init(const MD5_params *md5params);
-int Curl_MD5_update(MD5_context *context,
- const unsigned char *data,
- unsigned int len);
-int Curl_MD5_final(MD5_context *context, unsigned char *result);
+CURLcode Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len);
+CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result);
#endif
diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h
index fccf46879..ce38a08cd 100644
--- a/Utilities/cmcurl/lib/curl_memory.h
+++ b/Utilities/cmcurl/lib/curl_memory.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -39,7 +39,7 @@
*
* File lib/strdup.c is an exception, given that it provides a strdup
* clone implementation while using malloc. Extra care needed inside
- * this one. TODO: revisit this paragraph and related code.
+ * this one.
*
* The need for curl_memory.h inclusion is due to libcurl's feature
* of allowing library user to provide memory replacement functions,
diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c
index e78bb5002..e48334faf 100644
--- a/Utilities/cmcurl/lib/curl_multibyte.c
+++ b/Utilities/cmcurl/lib/curl_multibyte.c
@@ -64,13 +64,13 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w)
char *str_utf8 = NULL;
if(str_w) {
- int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
- 0, NULL, NULL);
- if(str_utf8_len > 0) {
- str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
+ int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1,
+ NULL, 0, NULL, NULL);
+ if(bytes > 0) {
+ str_utf8 = malloc(bytes);
if(str_utf8) {
- if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
- NULL, FALSE) == 0) {
+ if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes,
+ NULL, NULL) == 0) {
free(str_utf8);
return NULL;
}
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index 922e85a92..b6df38f71 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -38,7 +38,7 @@
3. USE_GNUTLS
4. USE_NSS
5. USE_MBEDTLS
- 6. USE_DARWINSSL
+ 6. USE_SECTRANSP
7. USE_OS400CRYPTO
8. USE_WIN32_CRYPTO
@@ -54,23 +54,15 @@
#ifdef USE_OPENSSL
-# ifdef USE_OPENSSL
-# include <openssl/des.h>
-# ifndef OPENSSL_NO_MD4
-# include <openssl/md4.h>
-# endif
-# include <openssl/md5.h>
-# include <openssl/ssl.h>
-# include <openssl/rand.h>
+# include <openssl/des.h>
+# ifndef OPENSSL_NO_MD4
+# include <openssl/md4.h>
# else
-# include <des.h>
-# ifndef OPENSSL_NO_MD4
-# include <md4.h>
-# endif
-# include <md5.h>
-# include <ssl.h>
-# include <rand.h>
+# include "curl_md4.h"
# endif
+# include <openssl/md5.h>
+# include <openssl/ssl.h>
+# include <openssl/rand.h>
# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
# define DES_key_schedule des_key_schedule
# define DES_cblock des_cblock
@@ -111,7 +103,7 @@
# include "curl_md4.h"
# endif
-#elif defined(USE_DARWINSSL)
+#elif defined(USE_SECTRANSP)
# include <CommonCrypto/CommonCryptor.h>
# include <CommonCrypto/CommonDigest.h>
@@ -300,7 +292,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
}
-#elif defined(USE_DARWINSSL)
+#elif defined(USE_SECTRANSP)
static bool encrypt_des(const unsigned char *in, unsigned char *out,
const unsigned char *key_56)
@@ -447,7 +439,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
setup_des_key(keys + 14, &des);
gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
gcry_cipher_close(des);
-#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(plaintext, results, keys);
encrypt_des(plaintext, results + 8, keys + 7);
@@ -511,7 +503,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
setup_des_key(pw + 7, &des);
gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
gcry_cipher_close(des);
-#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(magic, lmbuffer, pw);
encrypt_des(magic, lmbuffer + 8, pw + 7);
@@ -578,10 +570,14 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
{
/* Create NT hashed password. */
#ifdef USE_OPENSSL
+#if !defined(OPENSSL_NO_MD4)
MD4_CTX MD4pw;
MD4_Init(&MD4pw);
MD4_Update(&MD4pw, pw, 2 * len);
MD4_Final(ntbuffer, &MD4pw);
+#else
+ Curl_md4it(ntbuffer, pw, 2 * len);
+#endif
#elif defined(USE_GNUTLS_NETTLE)
struct md4_ctx MD4pw;
md4_init(&MD4pw);
@@ -601,7 +597,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
#else
Curl_md4it(ntbuffer, pw, 2 * len);
#endif
-#elif defined(USE_DARWINSSL)
+#elif defined(USE_SECTRANSP)
(void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
#elif defined(USE_OS400CRYPTO)
Curl_md4it(ntbuffer, pw, 2 * len);
@@ -631,9 +627,9 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
/* This returns the HMAC MD5 digest */
-CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
- const unsigned char *data, unsigned int datalen,
- unsigned char *output)
+static CURLcode hmac_md5(const unsigned char *key, unsigned int keylen,
+ const unsigned char *data, unsigned int datalen,
+ unsigned char *output)
{
HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen);
@@ -678,9 +674,8 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
ascii_uppercase_to_unicode_le(identity, user, userlen);
ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
- result = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len),
- ntlmv2hash);
-
+ result = hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len),
+ ntlmv2hash);
free(identity);
return result;
@@ -753,12 +748,12 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
return CURLE_OUT_OF_MEMORY;
/* Create the BLOB structure */
- snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN,
- "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
- "%c%c%c%c", /* Reserved = 0 */
- NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
- NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
- 0, 0, 0, 0);
+ msnprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN,
+ "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
+ "%c%c%c%c", /* Reserved = 0 */
+ NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
+ NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
+ 0, 0, 0, 0);
Curl_write64_le(tw, ptr + 24);
memcpy(ptr + 32, challenge_client, 8);
@@ -766,8 +761,8 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
/* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
memcpy(ptr + 8, &ntlm->nonce[0], 8);
- result = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8,
- NTLMv2_BLOB_LEN + 8, hmac_output);
+ result = hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8,
+ NTLMv2_BLOB_LEN + 8, hmac_output);
if(result) {
free(ptr);
return result;
@@ -809,7 +804,7 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
memcpy(&data[0], challenge_server, 8);
memcpy(&data[8], challenge_client, 8);
- result = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output);
+ result = hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output);
if(result)
return result;
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h
index 07ef5deae..3b4b8053c 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.h
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -43,9 +43,7 @@
/* Define USE_NTRESPONSES in order to make the type-3 message include
* the NT response message. */
-#if !defined(USE_OPENSSL) || !defined(OPENSSL_NO_MD4)
#define USE_NTRESPONSES
-#endif
/* Define USE_NTLM2SESSION in order to make the type-3 message include the
NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c
index a4791eb41..80266e2a4 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_wb.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -53,6 +53,8 @@
#include "url.h"
#include "strerror.h"
#include "strdup.h"
+#include "strcase.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -74,7 +76,7 @@
# define sclose_nolog(x) close((x))
#endif
-void Curl_ntlm_wb_cleanup(struct connectdata *conn)
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
{
if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
sclose(conn->ntlm_auth_hlpr_socket);
@@ -124,6 +126,7 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
struct passwd pw, *pw_res;
char pwbuf[1024];
#endif
+ char buffer[STRERROR_LEN];
/* Return if communication with ntlm_auth already set up */
if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
@@ -179,13 +182,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
if(access(ntlm_auth, X_OK) != 0) {
failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
- ntlm_auth, errno, Curl_strerror(conn, errno));
+ ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
failf(conn->data, "Could not open socket pair. errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
@@ -194,7 +197,7 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
sclose(sockfds[0]);
sclose(sockfds[1]);
failf(conn->data, "Could not fork. errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
else if(!child_pid) {
@@ -206,13 +209,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
sclose_nolog(sockfds[0]);
if(dup2(sockfds[1], STDIN_FILENO) == -1) {
failf(conn->data, "Could not redirect child stdin. errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
failf(conn->data, "Could not redirect child stdout. errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
@@ -232,7 +235,7 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
sclose_nolog(sockfds[1]);
failf(conn->data, "Could not execl(). errno %d: %s",
- errno, Curl_strerror(conn, errno));
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
@@ -332,6 +335,48 @@ done:
return CURLE_REMOTE_ACCESS_DENIED;
}
+CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
+ bool proxy,
+ const char *header)
+{
+ curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
+
+ if(!checkprefix("NTLM", header))
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ header += strlen("NTLM");
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(*header) {
+ conn->challenge_header = strdup(header);
+ if(!conn->challenge_header)
+ return CURLE_OUT_OF_MEMORY;
+
+ *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+ }
+ else {
+ if(*state == NTLMSTATE_LAST) {
+ infof(conn->data, "NTLM auth restarted\n");
+ Curl_http_auth_cleanup_ntlm_wb(conn);
+ }
+ else if(*state == NTLMSTATE_TYPE3) {
+ infof(conn->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");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+ }
+
+ return CURLE_OK;
+}
+
/*
* This is for creating ntlm header output by delegating challenge/response
* to Samba's winbind daemon helper ntlm_auth.
@@ -344,8 +389,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
char **allocuserpwd;
/* point to the name and password for this */
const char *userp;
- /* point to the correct struct with this */
- struct ntlmdata *ntlm;
+ curlntlm *state;
struct auth *authp;
CURLcode res = CURLE_OK;
@@ -357,13 +401,13 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
if(proxy) {
allocuserpwd = &conn->allocptr.proxyuserpwd;
userp = conn->http_proxy.user;
- ntlm = &conn->proxyntlm;
+ state = &conn->proxy_ntlm_state;
authp = &conn->data->state.authproxy;
}
else {
allocuserpwd = &conn->allocptr.userpwd;
userp = conn->user;
- ntlm = &conn->ntlm;
+ state = &conn->http_ntlm_state;
authp = &conn->data->state.authhost;
}
authp->done = FALSE;
@@ -372,7 +416,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
if(!userp)
userp = "";
- switch(ntlm->state) {
+ switch(*state) {
case NTLMSTATE_TYPE1:
default:
/* Use Samba's 'winbind' daemon to support NTLM authentication,
@@ -391,7 +435,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
res = ntlm_wb_init(conn, userp);
if(res)
return res;
- res = ntlm_wb_response(conn, "YR\n", ntlm->state);
+ res = ntlm_wb_response(conn, "YR\n", *state);
if(res)
return res;
@@ -405,11 +449,12 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
conn->response_header = NULL;
break;
+
case NTLMSTATE_TYPE2:
input = aprintf("TT %s\n", conn->challenge_header);
if(!input)
return CURLE_OUT_OF_MEMORY;
- res = ntlm_wb_response(conn, input, ntlm->state);
+ res = ntlm_wb_response(conn, input, *state);
free(input);
input = NULL;
if(res)
@@ -420,17 +465,20 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
proxy ? "Proxy-" : "",
conn->response_header);
DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
- ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+ *state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE;
- Curl_ntlm_wb_cleanup(conn);
+ Curl_http_auth_cleanup_ntlm_wb(conn);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
break;
+
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
* don't send a header in future requests */
- free(*allocuserpwd);
- *allocuserpwd = NULL;
+ *state = NTLMSTATE_LAST;
+ /* FALLTHROUGH */
+ case NTLMSTATE_LAST:
+ Curl_safefree(*allocuserpwd);
authp->done = TRUE;
break;
}
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.h b/Utilities/cmcurl/lib/curl_ntlm_wb.h
index aba3d469c..3cf841cf2 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_wb.h
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -27,11 +27,14 @@
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
defined(NTLM_WB_ENABLED)
-/* this is for creating ntlm header output by delegating challenge/response
- to Samba's winbind daemon helper ntlm_auth */
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm_wb(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);
-void Curl_ntlm_wb_cleanup(struct connectdata *conn);
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c
index 68f3e44ba..85dddcef1 100644
--- a/Utilities/cmcurl/lib/curl_path.c
+++ b/Utilities/cmcurl/lib/curl_path.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,6 +22,8 @@
#include "curl_setup.h"
+#if defined(USE_SSH)
+
#include <curl/curl.h>
#include "curl_memory.h"
#include "curl_path.h"
@@ -193,3 +195,5 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
Curl_safefree(*path);
return CURLE_QUOTE_ERROR;
}
+
+#endif /* if SSH is used */
diff --git a/Utilities/cmcurl/lib/curl_printf.h b/Utilities/cmcurl/lib/curl_printf.h
index 49857cdb0..0d37b8e57 100644
--- a/Utilities/cmcurl/lib/curl_printf.h
+++ b/Utilities/cmcurl/lib/curl_printf.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -31,7 +31,7 @@
# undef printf
# undef fprintf
-# undef snprintf
+# undef msnprintf
# undef vprintf
# undef vfprintf
# undef vsnprintf
@@ -39,18 +39,10 @@
# undef vaprintf
# define printf curl_mprintf
# define fprintf curl_mfprintf
-# define snprintf curl_msnprintf
+# define msnprintf curl_msnprintf
# define vprintf curl_mvprintf
# define vfprintf curl_mvfprintf
-# define vsnprintf curl_mvsnprintf
+# define mvsnprintf curl_mvsnprintf
# define aprintf curl_maprintf
# define vaprintf curl_mvaprintf
-
-/* We define away the sprintf functions unconditonally since we don't want
- internal code to be using them, intentionally or by mistake!*/
-# undef sprintf
-# undef vsprintf
-# define sprintf sprintf_was_used
-# define vsprintf vsprintf_was_used
-
#endif /* HEADER_CURL_PRINTF_H */
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index f09f2f332..16b1de1ae 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -239,17 +239,18 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
static CURLcode rtmp_do(struct connectdata *conn, bool *done)
{
+ struct Curl_easy *data = conn->data;
RTMP *r = conn->proto.generic;
if(!RTMP_ConnectStream(r, 0))
return CURLE_FAILED_INIT;
if(conn->data->set.upload) {
- Curl_pgrsSetUploadSize(conn->data, conn->data->state.infilesize);
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
}
else
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 354bc5448..018e4228b 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -31,6 +31,9 @@
#include "curl_setup.h"
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_POP3)
+
#include <curl/curl.h>
#include "urldata.h"
@@ -83,14 +86,14 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
#if defined(USE_KERBEROS5)
/* Cleanup the gssapi structure */
if(authused == SASL_MECH_GSSAPI) {
- Curl_auth_gssapi_cleanup(&conn->krb5);
+ Curl_auth_cleanup_gssapi(&conn->krb5);
}
#endif
#if defined(USE_NTLM)
/* Cleanup the NTLM structure */
if(authused == SASL_MECH_NTLM) {
- Curl_auth_ntlm_cleanup(&conn->ntlm);
+ Curl_auth_cleanup_ntlm(&conn->ntlm);
}
#endif
@@ -290,7 +293,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
#if defined(USE_KERBEROS5)
if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
Curl_auth_user_contains_domain(conn->user)) {
- sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
+ sasl->mutual_auth = FALSE;
mech = SASL_MECH_STRING_GSSAPI;
state1 = SASL_GSSAPI;
state2 = SASL_GSSAPI_TOKEN;
@@ -300,8 +303,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->easy_conn->
- host.name,
+ data->conn->host.name,
sasl->mutual_auth,
NULL, &conn->krb5,
&resp, &len);
@@ -358,10 +360,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
sasl->authused = SASL_MECH_XOAUTH2;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
- NULL, 0,
- conn->oauth_bearer,
- &resp, &len);
+ result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ conn->oauth_bearer,
+ &resp, &len);
}
else if(enabledmechs & SASL_MECH_PLAIN) {
mech = SASL_MECH_STRING_PLAIN;
@@ -369,8 +370,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
sasl->authused = SASL_MECH_PLAIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
- &resp, &len);
+ result = Curl_auth_create_plain_message(data, NULL, conn->user,
+ conn->passwd, &resp, &len);
}
else if(enabledmechs & SASL_MECH_LOGIN) {
mech = SASL_MECH_STRING_LOGIN;
@@ -452,9 +453,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
*progress = SASL_DONE;
return result;
case SASL_PLAIN:
- result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
- &resp,
- &len);
+ result = Curl_auth_create_plain_message(data, NULL, conn->user,
+ conn->passwd, &resp, &len);
break;
case SASL_LOGIN:
result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
@@ -517,7 +517,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->easy_conn->host.name,
+ data->conn->host.name,
sasl->mutual_auth, NULL,
&conn->krb5,
&resp, &len);
@@ -563,10 +563,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
newstate = SASL_OAUTH2_RESP;
}
else
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
- NULL, 0,
- conn->oauth_bearer,
- &resp, &len);
+ result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ conn->oauth_bearer,
+ &resp, &len);
break;
case SASL_OAUTH2_RESP:
@@ -627,3 +626,4 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
return result;
}
+#endif /* protocols are enabled that use SASL */
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 5cdbc5923..efba5ddec 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -314,11 +314,12 @@
#endif
#ifdef __AMIGA__
-# ifndef __ixemul__
-# include <exec/types.h>
-# include <exec/execbase.h>
-# include <proto/exec.h>
-# include <proto/dos.h>
+# include <exec/types.h>
+# include <exec/execbase.h>
+# include <proto/exec.h>
+# include <proto/dos.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
#endif
@@ -661,9 +662,9 @@ int netware_init(void);
#define LIBIDN_REQUIRED_VERSION "0.4.1"
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
- defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
+ defined(USE_POLARSSL) || defined(USE_MBEDTLS) || \
defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
- defined(USE_DARWINSSL) || defined(USE_GSKIT) || defined(USE_MESALINK)
+ defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK)
#define USE_SSL /* SSL support has been enabled */
#endif
@@ -682,7 +683,7 @@ 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) || \
- defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \
+ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \
defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
defined(USE_MBEDTLS)
@@ -700,6 +701,10 @@ int netware_init(void);
#error "No longer supported. Set CURLOPT_CAINFO at runtime instead."
#endif
+#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH)
+#define USE_SSH
+#endif
+
/*
* Provide a mechanism to silence picky compilers, such as gcc 4.6+.
* Parameters should of course normally not be unused, but for example when
@@ -831,4 +836,10 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
size_t buflen, struct passwd **result);
#endif
+#ifdef DEBUGBUILD
+#define UNITTEST
+#else
+#define UNITTEST static
+#endif
+
#endif /* HEADER_CURL_SETUP_H */
diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h
index 4c77d4f2e..3e9b516f8 100644
--- a/Utilities/cmcurl/lib/curlx.h
+++ b/Utilities/cmcurl/lib/curlx.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -81,22 +81,21 @@
# undef printf
# undef fprintf
# undef sprintf
-# undef snprintf
+# undef msnprintf
# undef vprintf
# undef vfprintf
# undef vsprintf
-# undef vsnprintf
+# undef mvsnprintf
# undef aprintf
# undef vaprintf
# define printf curlx_mprintf
# define fprintf curlx_mfprintf
# define sprintf curlx_msprintf
-# define snprintf curlx_msnprintf
+# define msnprintf curlx_msnprintf
# define vprintf curlx_mvprintf
# define vfprintf curlx_mvfprintf
-# define vsprintf curlx_mvsprintf
-# define vsnprintf curlx_mvsnprintf
+# define mvsnprintf curlx_mvsnprintf
# define aprintf curlx_maprintf
# define vaprintf curlx_mvaprintf
#endif /* ENABLE_CURLX_PRINTF */
diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c
index 78ef046d4..208a2336f 100644
--- a/Utilities/cmcurl/lib/dict.c
+++ b/Utilities/cmcurl/lib/dict.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -137,7 +137,6 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path = data->state.up.path;
- curl_off_t *bytecount = &data->req.bytecount;
*done = TRUE; /* unconditionally */
@@ -200,8 +199,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
failf(data, "Failed sending DICT request");
return result;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL); /* no upload */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
}
else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
@@ -247,8 +245,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
failf(data, "Failed sending DICT request");
return result;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL); /* no upload */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
}
else {
@@ -270,7 +267,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
return result;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
}
}
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index ef6013db9..6d1f3303b 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2019, 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
@@ -22,17 +22,19 @@
#include "curl_setup.h"
+#ifndef CURL_DISABLE_DOH
+
#include "urldata.h"
#include "curl_addrinfo.h"
#include "doh.h"
-#ifdef USE_NGHTTP2
#include "sendf.h"
#include "multiif.h"
#include "url.h"
#include "share.h"
#include "curl_base64.h"
#include "connect.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -143,8 +145,8 @@ doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp)
/* suspiciously much for us */
return 0;
- mem->memory = realloc(mem->memory, mem->size + realsize);
- if(mem->memory == NULL)
+ mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize);
+ if(!mem->memory)
/* out of memory! */
return 0;
@@ -160,7 +162,7 @@ static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
struct Curl_easy *data = doh->set.dohfor;
/* 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, %d to go\n", data->req.doh.pending);
+ infof(data, "a DOH request is completed, %u to go\n", data->req.doh.pending);
if(result)
infof(data, "DOH request %s\n", curl_easy_strerror(result));
@@ -173,8 +175,12 @@ static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
return 0;
}
-#define ERROR_CHECK_SETOPT(x,y) result = curl_easy_setopt(doh, x, y); \
- if(result) goto error
+#define ERROR_CHECK_SETOPT(x,y) \
+do { \
+ result = curl_easy_setopt(doh, x, y); \
+ if(result) \
+ goto error; \
+} WHILE_FALSE
static CURLcode dohprobe(struct Curl_easy *data,
struct dnsprobe *p, DNStype dnstype,
@@ -234,13 +240,76 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
}
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
+#ifdef USE_NGHTTP2
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+#endif
#ifndef CURLDEBUG
/* enforce HTTPS if not debug */
ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#endif
ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
- ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+ if(data->set.verbose)
+ ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+ if(data->set.no_signal)
+ ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
+
+ /* Inherit *some* SSL options from the user's transfer. This is a
+ best-guess as to which options are needed for compatibility. #3661 */
+ if(data->set.ssl.falsestart)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
+ if(data->set.ssl.primary.verifyhost)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, 2L);
+ if(data->set.proxy_ssl.primary.verifyhost)
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYHOST, 2L);
+ if(data->set.ssl.primary.verifypeer)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
+ if(data->set.proxy_ssl.primary.verifypeer)
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
+ if(data->set.ssl.primary.verifystatus)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, 1L);
+ if(data->set.str[STRING_SSL_CAFILE_ORIG]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
+ data->set.str[STRING_SSL_CAFILE_ORIG]);
+ }
+ if(data->set.str[STRING_SSL_CAFILE_PROXY]) {
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO,
+ data->set.str[STRING_SSL_CAFILE_PROXY]);
+ }
+ if(data->set.str[STRING_SSL_CAPATH_ORIG]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
+ data->set.str[STRING_SSL_CAPATH_ORIG]);
+ }
+ if(data->set.str[STRING_SSL_CAPATH_PROXY]) {
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH,
+ data->set.str[STRING_SSL_CAPATH_PROXY]);
+ }
+ if(data->set.str[STRING_SSL_CRLFILE_ORIG]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
+ data->set.str[STRING_SSL_CRLFILE_ORIG]);
+ }
+ if(data->set.str[STRING_SSL_CRLFILE_PROXY]) {
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE,
+ data->set.str[STRING_SSL_CRLFILE_PROXY]);
+ }
+ if(data->set.ssl.certinfo)
+ ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
+ if(data->set.str[STRING_SSL_RANDOM_FILE]) {
+ ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE,
+ data->set.str[STRING_SSL_RANDOM_FILE]);
+ }
+ if(data->set.str[STRING_SSL_EGDSOCKET]) {
+ ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET,
+ data->set.str[STRING_SSL_EGDSOCKET]);
+ }
+ if(data->set.ssl.no_revoke)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
+ if(data->set.proxy_ssl.no_revoke)
+ ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
+ if(data->set.ssl.fsslctx)
+ 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);
+
doh->set.fmultidone = Curl_doh_done;
doh->set.dohfor = data; /* identify for which transfer this is done */
p->easy = doh;
@@ -515,7 +584,6 @@ UNITTEST DOHcode doh_decode(unsigned char *doh,
unsigned short qdcount;
unsigned short ancount;
unsigned short type = 0;
- unsigned short class;
unsigned short rdlength;
unsigned short nscount;
unsigned short arcount;
@@ -524,7 +592,7 @@ UNITTEST DOHcode doh_decode(unsigned char *doh,
if(dohlen < 12)
return DOH_TOO_SMALL_BUFFER; /* too small */
- if(doh[0] || doh[1])
+ if(!doh || doh[0] || doh[1])
return DOH_DNS_BAD_ID; /* bad ID */
rcode = doh[3] & 0x0f;
if(rcode)
@@ -543,6 +611,7 @@ UNITTEST DOHcode doh_decode(unsigned char *doh,
ancount = get16bit(doh, 6);
while(ancount) {
+ unsigned short class;
unsigned int ttl;
rc = skipqname(doh, dohlen, &index);
@@ -660,13 +729,13 @@ static void showdoh(struct Curl_easy *data,
char buffer[128];
char *ptr;
size_t len;
- snprintf(buffer, 128, "DOH AAAA: ");
+ msnprintf(buffer, 128, "DOH AAAA: ");
ptr = &buffer[10];
len = 118;
for(j = 0; j < 16; j += 2) {
size_t l;
- snprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
- d->addr[i].ip.v6[j + 1]);
+ msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
+ d->addr[i].ip.v6[j + 1]);
l = strlen(ptr);
len -= l;
ptr += l;
@@ -827,8 +896,6 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
DOHcode rc;
DOHcode rc2;
struct dohentry de;
- struct Curl_dns_entry *dns;
- struct Curl_addrinfo *ai;
/* remove DOH handles from multi handle and close them */
curl_multi_remove_handle(data->multi, data->req.doh.probe[0].easy);
Curl_close(data->req.doh.probe[0].easy);
@@ -853,11 +920,14 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
&de);
free(data->req.doh.probe[1].serverdoh.memory);
if(rc2) {
- infof(data, "DOG: %s type %s for %s\n", doh_strerror(rc2),
+ infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc2),
type2name(data->req.doh.probe[1].dnstype),
data->req.doh.host);
}
if(!rc || !rc2) {
+ struct Curl_dns_entry *dns;
+ struct Curl_addrinfo *ai;
+
infof(data, "DOH Host name: %s\n", data->req.doh.host);
showdoh(data, &de);
@@ -894,27 +964,4 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
return CURLE_OK;
}
-#else /* !USE_NGHTTP2 */
-/*
- */
-Curl_addrinfo *Curl_doh(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- (void)conn;
- (void)hostname;
- (void)port;
- (void)waitp;
- return NULL;
-}
-
-CURLcode Curl_doh_is_resolved(struct connectdata *conn,
- struct Curl_dns_entry **dnsp)
-{
- (void)conn;
- (void)dnsp;
- return CURLE_NOT_BUILT_IN;
-}
-
-#endif /* USE_NGHTTP2 */
+#endif /* CURL_DISABLE_DOH */
diff --git a/Utilities/cmcurl/lib/doh.h b/Utilities/cmcurl/lib/doh.h
index 83c79bc5d..34bfa6f2b 100644
--- a/Utilities/cmcurl/lib/doh.h
+++ b/Utilities/cmcurl/lib/doh.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2019, 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
@@ -25,6 +25,8 @@
#include "urldata.h"
#include "curl_addrinfo.h"
+#ifndef CURL_DISABLE_DOH
+
/*
* Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name
* and returns a 'Curl_addrinfo *' with the address information.
@@ -102,4 +104,10 @@ DOHcode doh_decode(unsigned char *doh,
struct dohentry *d);
void de_cleanup(struct dohentry *d);
#endif
+
+#else /* if DOH is disabled */
+#define Curl_doh(a,b,c,d) NULL
+#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#endif
+
#endif /* HEADER_CURL_DOH_H */
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 4de4e6522..4a6f96567 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -75,6 +75,7 @@
#include "ssh.h"
#include "setopt.h"
#include "http_digest.h"
+#include "system_win32.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -83,70 +84,6 @@
void Curl_version_init(void);
-/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
- of win32_init() */
-static void win32_cleanup(void)
-{
-#ifdef USE_WINSOCK
- WSACleanup();
-#endif
-#ifdef USE_WINDOWS_SSPI
- Curl_sspi_global_cleanup();
-#endif
-}
-
-/* win32_init() performs win32 socket initialization to properly setup the
- stack to allow networking */
-static CURLcode win32_init(void)
-{
-#ifdef USE_WINSOCK
- WORD wVersionRequested;
- WSADATA wsaData;
- int res;
-
-#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
- Error IPV6_requires_winsock2
-#endif
-
- wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
-
- res = WSAStartup(wVersionRequested, &wsaData);
-
- if(res != 0)
- /* Tell the user that we couldn't find a usable */
- /* winsock.dll. */
- return CURLE_FAILED_INIT;
-
- /* Confirm that the Windows Sockets DLL supports what we need.*/
- /* Note that if the DLL supports versions greater */
- /* than wVersionRequested, it will still return */
- /* wVersionRequested in wVersion. wHighVersion contains the */
- /* highest supported version. */
-
- if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
- HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
- /* Tell the user that we couldn't find a usable */
-
- /* winsock.dll. */
- WSACleanup();
- return CURLE_FAILED_INIT;
- }
- /* The Windows Sockets DLL is acceptable. Proceed. */
-#elif defined(USE_LWIPSOCK)
- lwip_init();
-#endif
-
-#ifdef USE_WINDOWS_SSPI
- {
- CURLcode result = Curl_sspi_global_init();
- if(result)
- return result;
- }
-#endif
-
- return CURLE_OK;
-}
-
/* true globals -- for curl_global_init() and curl_global_cleanup() */
static unsigned int initialized;
static long init_flags;
@@ -223,11 +160,12 @@ static CURLcode global_init(long flags, bool memoryfuncs)
return CURLE_FAILED_INIT;
}
- if(flags & CURL_GLOBAL_WIN32)
- if(win32_init()) {
- DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
- return CURLE_FAILED_INIT;
- }
+#ifdef WIN32
+ if(Curl_win32_init(flags)) {
+ DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+#endif
#ifdef __AMIGA__
if(!Curl_amiga_init()) {
@@ -327,12 +265,12 @@ void curl_global_cleanup(void)
if(--initialized)
return;
- Curl_global_host_cache_dtor();
Curl_ssl_cleanup();
Curl_resolver_global_cleanup();
- if(init_flags & CURL_GLOBAL_WIN32)
- win32_cleanup();
+#ifdef WIN32
+ Curl_win32_cleanup(init_flags);
+#endif
Curl_amiga_cleanup();
@@ -489,8 +427,8 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
mask. Convert from libcurl bitmask to the poll one. */
m->socket.events = socketcb2poll(what);
infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
- what&CURL_POLL_IN?"IN":"",
- what&CURL_POLL_OUT?"OUT":"");
+ (what&CURL_POLL_IN)?"IN":"",
+ (what&CURL_POLL_OUT)?"OUT":"");
}
break;
}
@@ -513,8 +451,8 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
m->socket.revents = 0;
ev->list = m;
infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
- what&CURL_POLL_IN?"IN":"",
- what&CURL_POLL_OUT?"OUT":"");
+ (what&CURL_POLL_IN)?"IN":"",
+ (what&CURL_POLL_OUT)?"OUT":"");
}
else
return CURLE_OUT_OF_MEMORY;
@@ -621,7 +559,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
return CURLE_RECV_ERROR;
if(mcode)
- return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */
+ return CURLE_URL_MALFORMAT;
/* we don't really care about the "msgs_in_queue" value returned in the
second argument */
@@ -664,12 +602,12 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
while(!done && !mcode) {
int still_running = 0;
- int rc;
+ bool gotsocket = FALSE;
- mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
+ mcode = Curl_multi_wait(multi, NULL, 0, 1000, NULL, &gotsocket);
if(!mcode) {
- if(!rc) {
+ if(!gotsocket) {
long sleep_ms;
/* If it returns without any filedescriptor instantly, we need to
@@ -688,6 +626,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
/* only read 'still_running' if curl_multi_perform() return OK */
if(!mcode && !still_running) {
+ int rc;
CURLMsg *msg = curl_multi_info_read(multi, &rc);
if(msg) {
result = msg->data.result;
@@ -966,7 +905,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
}
/* Clone the resolver handle, if present, for the new handle */
- if(Curl_resolver_duphandle(&outcurl->state.resolver,
+ if(Curl_resolver_duphandle(outcurl,
+ &outcurl->state.resolver,
data->state.resolver))
goto fail;
@@ -1021,7 +961,10 @@ void curl_easy_reset(struct Curl_easy *data)
/* zero out authentication data: */
memset(&data->state.authhost, 0, sizeof(struct auth));
memset(&data->state.authproxy, 0, sizeof(struct auth));
- Curl_digest_cleanup(data);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+ Curl_http_auth_cleanup_digest(data);
+#endif
}
/*
@@ -1058,7 +1001,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
unsigned int i;
unsigned int count = data->state.tempcount;
struct tempbuf writebuf[3]; /* there can only be three */
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
struct Curl_easy *saved_data = NULL;
/* copy the structs to allow for immediate re-pausing */
diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c
index afd3899f9..7121db31c 100644
--- a/Utilities/cmcurl/lib/escape.c
+++ b/Utilities/cmcurl/lib/escape.c
@@ -122,7 +122,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
return NULL;
}
- snprintf(&ns[strindex], 4, "%%%02X", in);
+ msnprintf(&ns[strindex], 4, "%%%02X", in);
strindex += 3;
}
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
index 722b55e9d..d349cd924 100644
--- a/Utilities/cmcurl/lib/file.c
+++ b/Utilities/cmcurl/lib/file.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -311,7 +311,7 @@ static CURLcode file_upload(struct connectdata *conn)
if(result)
break;
- if(readcount <= 0) /* fix questionable compare error. curlvms */
+ if(!readcount)
break;
nread = readcount;
@@ -417,8 +417,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
struct tm buffer;
const struct tm *tm = &buffer;
char header[80];
- snprintf(header, sizeof(header),
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
+ 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;
@@ -434,16 +435,16 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
return result;
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- snprintf(header, sizeof(header),
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec,
- data->set.opt_no_body ? "": "\r\n");
+ msnprintf(header, sizeof(header),
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ data->set.opt_no_body ? "": "\r\n");
result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
if(result)
return result;
diff --git a/Utilities/cmcurl/lib/fileinfo.c b/Utilities/cmcurl/lib/fileinfo.c
index 4e72e1eba..2630c9e46 100644
--- a/Utilities/cmcurl/lib/fileinfo.c
+++ b/Utilities/cmcurl/lib/fileinfo.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2019, 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
@@ -21,7 +21,7 @@
***************************************************************************/
#include "curl_setup.h"
-
+#ifndef CURL_DISABLE_FTP
#include "strdup.h"
#include "fileinfo.h"
#include "curl_memory.h"
@@ -41,3 +41,4 @@ void Curl_fileinfo_cleanup(struct fileinfo *finfo)
Curl_safefree(finfo->info.b_data);
free(finfo);
}
+#endif
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index 202d930c7..429d479da 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -24,14 +24,14 @@
#include <curl/curl.h>
-#ifndef CURL_DISABLE_HTTP
+#include "formdata.h"
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
#include <libgen.h>
#endif
#include "urldata.h" /* for struct Curl_easy */
-#include "formdata.h"
#include "mime.h"
#include "non-ascii.h"
#include "vtls/vtls.h"
@@ -569,7 +569,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(((form->flags & HTTPPOST_FILENAME) ||
(form->flags & HTTPPOST_BUFFER)) &&
!form->contenttype) {
- char *f = form->flags & HTTPPOST_BUFFER?
+ char *f = (form->flags & HTTPPOST_BUFFER)?
form->showfilename : form->value;
char const *type;
type = Curl_mime_contenttype(f);
@@ -921,7 +921,8 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
return result;
}
-#else /* CURL_DISABLE_HTTP */
+#else
+/* if disabled */
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
struct curl_httppost **last_post,
...)
@@ -946,5 +947,4 @@ void curl_formfree(struct curl_httppost *form)
/* does nothing HTTP is disabled */
}
-
-#endif /* !defined(CURL_DISABLE_HTTP) */
+#endif /* if disabled */
diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h
index 1246c2bc8..cb20805f5 100644
--- a/Utilities/cmcurl/lib/formdata.h
+++ b/Utilities/cmcurl/lib/formdata.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,6 +22,10 @@
*
***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_MIME
+
/* used by FormAdd for temporary storage */
typedef struct FormInfo {
char *name;
@@ -47,5 +51,10 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
curl_mimepart *,
struct curl_httppost *post,
curl_read_callback fread_func);
+#else
+/* disabled */
+#define Curl_getformdata(a,b,c,d) CURLE_NOT_BUILT_IN
+#endif
+
#endif /* HEADER_CURL_FORMDATA_H */
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index ce889ab29..53510f821 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -448,7 +448,6 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
static CURLcode InitiateTransfer(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
CURLcode result = CURLE_OK;
if(conn->bits.ftp_use_data_ssl) {
@@ -461,24 +460,19 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
}
if(conn->proto.ftpc.state_saved == FTP_STOR) {
- *(ftp->bytecountp) = 0;
-
/* When we know we're uploading a specified file, we can get the file
size prior to the actual upload. */
-
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* set the SO_SNDBUF for the secondary socket for those who need it */
Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
- SECONDARYSOCKET, ftp->bytecountp);
+ Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
}
else {
/* FTP download: */
- Curl_setup_transfer(conn, SECONDARYSOCKET,
- conn->proto.ftpc.retr_size_saved, FALSE,
- ftp->bytecountp, -1, NULL); /* no upload here */
+ Curl_setup_transfer(data, SECONDARYSOCKET,
+ conn->proto.ftpc.retr_size_saved, FALSE, -1);
}
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@@ -578,7 +572,6 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
#if defined(HAVE_GSSAPI)
/* handle the security-oriented responses 6xx ***/
- /* FIXME: some errorchecking perhaps... ***/
switch(code) {
case 631:
code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
@@ -655,7 +648,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
while(!*ftpcode && !result) {
/* check and reset timeout value every lap */
- time_t timeout = Curl_pp_state_timeout(pp); /* timeout in milliseconds */
+ time_t timeout = Curl_pp_state_timeout(pp, FALSE);
time_t interval_ms;
if(timeout <= 0) {
@@ -955,7 +948,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
unsigned short port_max = 0;
unsigned short port;
bool possibly_non_local = TRUE;
-
+ char buffer[STRERROR_LEN];
char *addr = NULL;
/* Step 1, figure out what is requested,
@@ -1064,11 +1057,10 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
if(!host) {
/* not an interface and not a host name, get default by extracting
the IP from the control connection */
-
sslen = sizeof(ss);
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
free(addr);
return CURLE_FTP_PORT_FAILED;
}
@@ -1087,7 +1079,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
}
/* resolv ip/host to ip */
- rc = Curl_resolv(conn, host, 0, &h);
+ rc = Curl_resolv(conn, host, 0, FALSE, &h);
if(rc == CURLRESOLV_PENDING)
(void)Curl_resolver_wait_resolv(conn, &h);
if(h) {
@@ -1121,7 +1113,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
break;
}
if(!ai) {
- failf(data, "socket failure: %s", Curl_strerror(conn, error));
+ failf(data, "socket failure: %s",
+ Curl_strerror(error, buffer, sizeof(buffer)));
return CURLE_FTP_PORT_FAILED;
}
@@ -1145,14 +1138,13 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
/* The requested bind address is not local. Use the address used for
* the control connection instead and restart the port loop
*/
-
infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
- Curl_strerror(conn, error) );
+ Curl_strerror(error, buffer, sizeof(buffer)));
sslen = sizeof(ss);
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
Curl_closesocket(conn, portsock);
return CURLE_FTP_PORT_FAILED;
}
@@ -1162,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(conn, error) );
+ Curl_strerror(error, buffer, sizeof(buffer)));
Curl_closesocket(conn, portsock);
return CURLE_FTP_PORT_FAILED;
}
@@ -1185,7 +1177,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
sslen = sizeof(ss);
if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
Curl_closesocket(conn, portsock);
return CURLE_FTP_PORT_FAILED;
}
@@ -1193,7 +1185,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
/* step 4, listen on the socket */
if(listen(portsock, 1)) {
- failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
+ failf(data, "socket failure: %s",
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
Curl_closesocket(conn, portsock);
return CURLE_FTP_PORT_FAILED;
}
@@ -1272,7 +1265,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
source++;
}
*dest = 0;
- snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+ msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
if(result) {
@@ -1658,7 +1651,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
infof(data, "File already completely uploaded\n");
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
/* Set ->transfer so that we won't get any error in
* ftp_done() because we didn't transfer anything! */
@@ -1940,7 +1933,7 @@ 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, &addr);
+ rc = Curl_resolv(conn, 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 */
@@ -1956,7 +1949,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
}
else {
/* normal, direct, ftp connection */
- rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
+ rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr);
if(rc == CURLRESOLV_PENDING)
/* BLOCKING */
(void)Curl_resolver_wait_resolv(conn, &addr);
@@ -2061,9 +2054,9 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
char timebuf[24];
time_t secs = time(NULL);
- snprintf(timebuf, sizeof(timebuf),
- "%04d%02d%02d %02d:%02d:%02d GMT",
- year, month, day, hour, minute, second);
+ msnprintf(timebuf, sizeof(timebuf),
+ "%04d%02d%02d %02d:%02d:%02d GMT",
+ year, month, day, hour, minute, second);
/* now, convert this into a time() value: */
data->info.filetime = curl_getdate(timebuf, &secs);
}
@@ -2086,15 +2079,15 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
return result;
/* format: "Tue, 15 Nov 1994 12:45:26" */
- snprintf(headerbuf, sizeof(headerbuf),
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
+ msnprintf(headerbuf, sizeof(headerbuf),
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
if(result)
return result;
@@ -2230,7 +2223,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
if(ftp->downloadsize == 0) {
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded\n");
/* Set ->transfer so that we won't get any error in ftp_done()
@@ -2276,8 +2269,8 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
#ifdef CURL_FTP_HTTPSTYLE_HEAD
if(-1 != filesize) {
char clbuf[128];
- snprintf(clbuf, sizeof(clbuf),
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
+ msnprintf(clbuf, sizeof(clbuf),
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
if(result)
return result;
@@ -3054,7 +3047,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn,
bool *done)
{
struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
+ CURLcode result = Curl_pp_statemach(&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
@@ -3071,7 +3064,7 @@ static CURLcode ftp_block_statemach(struct connectdata *conn)
CURLcode result = CURLE_OK;
while(ftpc->state != FTP_STOP) {
- result = Curl_pp_statemach(pp, TRUE);
+ result = Curl_pp_statemach(pp, TRUE, TRUE /* disconnecting */);
if(result)
break;
}
@@ -3308,33 +3301,33 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
;
else if(data->set.upload) {
if((-1 != data->state.infilesize) &&
- (data->state.infilesize != *ftp->bytecountp) &&
+ (data->state.infilesize != data->req.writebytecount) &&
!data->set.crlf &&
(ftp->transfer == FTPTRANSFER_BODY)) {
failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
" out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
- *ftp->bytecountp, data->state.infilesize);
+ data->req.bytecount, data->state.infilesize);
result = CURLE_PARTIAL_FILE;
}
}
else {
if((-1 != data->req.size) &&
- (data->req.size != *ftp->bytecountp) &&
+ (data->req.size != data->req.bytecount) &&
#ifdef CURL_DO_LINEEND_CONV
/* Most FTP servers don't adjust their file SIZE response for CRLFs, so
* we'll check to see if the discrepancy can be explained by the number
* of CRLFs we've changed to LFs.
*/
((data->req.size + data->state.crlf_conversions) !=
- *ftp->bytecountp) &&
+ data->req.bytecount) &&
#endif /* CURL_DO_LINEEND_CONV */
- (data->req.maxdownload != *ftp->bytecountp)) {
+ (data->req.maxdownload != data->req.bytecount)) {
failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
- " bytes", *ftp->bytecountp);
+ " bytes", data->req.bytecount);
result = CURLE_PARTIAL_FILE;
}
else if(!ftpc->dont_check &&
- !*ftp->bytecountp &&
+ !data->req.bytecount &&
(data->req.size>0)) {
failf(data, "No data was received!");
result = CURLE_FTP_COULDNT_RETR_FILE;
@@ -3496,7 +3489,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
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. TODO: make this nicer */
+ aren't used so we blank their arguments. */
result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
return result;
@@ -3629,7 +3622,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
if(!result && (ftp->transfer != FTPTRANSFER_BODY))
/* no data to transfer. FIX: it feels like a kludge to have this here
too! */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
@@ -4309,7 +4302,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn,
if(ftp->transfer != FTPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(conn->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;
@@ -4396,7 +4389,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
return CURLE_OUT_OF_MEMORY;
ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
- data->state.slash_removed = TRUE; /* we've skipped the slash */
/* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */
@@ -4429,7 +4421,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
}
/* get some initial data into the ftp struct */
- ftp->bytecountp = &conn->data->req.bytecount;
ftp->transfer = FTPTRANSFER_BODY;
ftp->downloadsize = 0;
diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h
index 38d03223c..828d69a21 100644
--- a/Utilities/cmcurl/lib/ftp.h
+++ b/Utilities/cmcurl/lib/ftp.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -102,7 +102,6 @@ typedef enum {
perhaps the Curl_easy is changed between the times the connection is
used. */
struct FTP {
- curl_off_t *bytecountp;
char *user; /* user name string */
char *passwd; /* password string */
char *path; /* points to the urlpieces struct field */
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index 249fe09c8..c4eb43732 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -405,7 +405,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.main = PL_UNIX_FILETYPE;
/* start FSM again not considering size of directory */
finfo->b_used = 0;
- i--;
+ continue;
}
break;
case PL_UNIX_TOTALSIZE_READING:
@@ -914,10 +914,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
case PL_WINNT_DIRORSIZE:
switch(parser->state.NT.sub.dirorsize) {
case PL_WINNT_DIRORSIZE_PRESPACE:
- if(c == ' ') {
-
- }
- else {
+ if(c != ' ') {
parser->item_offset = finfo->b_used - 1;
parser->item_length = 1;
parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
index 54c2c2f1c..e118da80d 100644
--- a/Utilities/cmcurl/lib/getinfo.c
+++ b/Utilities/cmcurl/lib/getinfo.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -163,10 +163,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
*param_longp = (long)data->info.filetime;
break;
case CURLINFO_HEADER_SIZE:
- *param_longp = data->info.header_size;
+ *param_longp = (long)data->info.header_size;
break;
case CURLINFO_REQUEST_SIZE:
- *param_longp = data->info.request_size;
+ *param_longp = (long)data->info.request_size;
break;
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->set.ssl.certverifyresult;
@@ -390,7 +390,7 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
param_slistp;
struct curl_tlssessioninfo *tsi = &data->tsi;
#ifdef USE_SSL
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
#endif
*tsip = tsi;
diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c
index b441a641d..b296c62d1 100644
--- a/Utilities/cmcurl/lib/gopher.c
+++ b/Utilities/cmcurl/lib/gopher.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -31,9 +31,11 @@
#include "progress.h"
#include "gopher.h"
#include "select.h"
+#include "strdup.h"
#include "url.h"
#include "escape.h"
#include "warnless.h"
+#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
@@ -76,9 +78,9 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-
- curl_off_t *bytecount = &data->req.bytecount;
+ char *gopherpath;
char *path = data->state.up.path;
+ char *query = data->state.up.query;
char *sel = NULL;
char *sel_org = NULL;
ssize_t amount, k;
@@ -86,20 +88,33 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
*done = TRUE; /* unconditionally */
+ /* path is guaranteed non-NULL */
+ DEBUGASSERT(path);
+
+ if(query)
+ gopherpath = aprintf("%s?%s", path, query);
+ else
+ gopherpath = strdup(path);
+
+ if(!gopherpath)
+ return CURLE_OUT_OF_MEMORY;
+
/* Create selector. Degenerate cases: / and /1 => convert to "" */
- if(strlen(path) <= 2) {
+ if(strlen(gopherpath) <= 2) {
sel = (char *)"";
len = strlen(sel);
+ free(gopherpath);
}
else {
char *newp;
/* Otherwise, drop / and the first character (i.e., item type) ... */
- newp = path;
+ newp = gopherpath;
newp += 2;
/* ... and finally unescape */
result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
+ free(gopherpath);
if(result)
return result;
sel_org = sel;
@@ -153,8 +168,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
if(result)
return result;
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL); /* no upload */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
return CURLE_OK;
}
#endif /*CURL_DISABLE_GOPHER*/
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
index 6ff60ba61..99d872b35 100644
--- a/Utilities/cmcurl/lib/hostasyn.c
+++ b/Utilities/cmcurl/lib/hostasyn.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -85,14 +85,14 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
dns = Curl_cache_addr(data, ai,
conn->async.hostname,
conn->async.port);
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
if(!dns) {
/* failed to store, cleanup and return error */
Curl_freeaddrinfo(ai);
result = CURLE_OUT_OF_MEMORY;
}
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
else {
result = CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c
index c9d8112d8..115d24b2e 100644
--- a/Utilities/cmcurl/lib/hostcheck.c
+++ b/Utilities/cmcurl/lib/hostcheck.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -23,7 +23,6 @@
#include "curl_setup.h"
#if defined(USE_OPENSSL) \
- || defined(USE_AXTLS) \
|| defined(USE_GSKIT) \
|| defined(USE_SCHANNEL)
/* these backends use functions from this file */
@@ -128,16 +127,14 @@ static int hostmatch(char *hostname, char *pattern)
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
{
- char *matchp;
- char *hostp;
int res = 0;
if(!match_pattern || !*match_pattern ||
!hostname || !*hostname) /* sanity check */
;
else {
- matchp = strdup(match_pattern);
+ char *matchp = strdup(match_pattern);
if(matchp) {
- hostp = strdup(hostname);
+ char *hostp = strdup(hostname);
if(hostp) {
if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
res = 1;
@@ -150,4 +147,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
return res;
}
-#endif /* OPENSSL, AXTLS, GSKIT or schannel+wince */
+#endif /* OPENSSL, GSKIT or schannel+wince */
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index f589a0b2c..cf33ed8f4 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -73,6 +73,8 @@
#define USE_ALARM_TIMEOUT
#endif
+#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
+
/*
* hostip.c explained
* ==================
@@ -112,43 +114,9 @@
* CURLRES_* defines based on the config*.h and curl_setup.h defines.
*/
-/* These two symbols are for the global DNS cache */
-static struct curl_hash hostname_cache;
-static int host_cache_initialized;
-
static void freednsentry(void *freethis);
/*
- * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
- * 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.
- */
-struct curl_hash *Curl_global_host_cache_init(void)
-{
- int rc = 0;
- if(!host_cache_initialized) {
- rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
- Curl_str_key_compare, freednsentry);
- if(!rc)
- host_cache_initialized = 1;
- }
- return rc?NULL:&hostname_cache;
-}
-
-/*
- * Destroy and cleanup the global DNS cache
- */
-void Curl_global_host_cache_dtor(void)
-{
- if(host_cache_initialized) {
- Curl_hash_destroy(&hostname_cache);
- host_cache_initialized = 0;
- }
-}
-
-/*
* Return # of addresses in a Curl_addrinfo struct
*/
int Curl_num_addresses(const Curl_addrinfo *addr)
@@ -198,23 +166,19 @@ Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
}
/*
- * Return a hostcache id string for the provided host + port, to be used by
- * the DNS caching.
+ * Create a hostcache id string for the provided host + port, to be used by
+ * the DNS caching. Without alloc.
*/
-static char *
-create_hostcache_id(const char *name, int port)
+static void
+create_hostcache_id(const char *name, int port, char *ptr, size_t buflen)
{
- /* create and return the new allocated entry */
- char *id = aprintf("%s:%d", name, port);
- char *ptr = id;
- if(ptr) {
- /* lower case the name part */
- while(*ptr && (*ptr != ':')) {
- *ptr = (char)TOLOWER(*ptr);
- ptr++;
- }
- }
- return id;
+ size_t len = strlen(name);
+ if(len > (buflen - 7))
+ len = buflen - 7;
+ /* store and lower case the name */
+ while(len--)
+ *ptr++ = (char)TOLOWER(*name++);
+ msnprintf(ptr, 7, ":%u", port);
}
struct hostcache_prune_data {
@@ -296,22 +260,27 @@ fetch_addr(struct connectdata *conn,
const char *hostname,
int port)
{
- char *entry_id = NULL;
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 */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if(!entry_id)
- return dns;
-
+ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
entry_len = strlen(entry_id);
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+ /* No entry found in cache, check if we might have a wildcard entry */
+ if(!dns && data->change.wildcard_resolve) {
+ create_hostcache_id("*", port, entry_id, sizeof(entry_id));
+ entry_len = strlen(entry_id);
+
+ /* See if it's already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+ }
+
if(dns && (data->set.dns_cache_timeout != -1)) {
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
@@ -326,9 +295,6 @@ fetch_addr(struct connectdata *conn,
}
}
- /* free the allocated entry_id again */
- free(entry_id);
-
return dns;
}
@@ -368,6 +334,9 @@ Curl_fetch_addr(struct connectdata *conn,
return dns;
}
+#ifndef CURL_DISABLE_SHUFFLE_DNS
+UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
+ Curl_addrinfo **addr);
/*
* Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
* struct by re-linking its linked list.
@@ -380,7 +349,8 @@ Curl_fetch_addr(struct connectdata *conn,
*
* @unittest: 1608
*/
-CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr)
+UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
+ Curl_addrinfo **addr)
{
CURLcode result = CURLE_OK;
const int num_addrs = Curl_num_addresses(*addr);
@@ -431,6 +401,7 @@ CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr)
}
return result;
}
+#endif
/*
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
@@ -447,32 +418,30 @@ Curl_cache_addr(struct Curl_easy *data,
const char *hostname,
int port)
{
- char *entry_id;
+ char entry_id[MAX_HOSTCACHE_LEN];
size_t entry_len;
struct Curl_dns_entry *dns;
struct Curl_dns_entry *dns2;
+#ifndef CURL_DISABLE_SHUFFLE_DNS
/* shuffle addresses if requested */
if(data->set.dns_shuffle_addresses) {
CURLcode result = Curl_shuffle_addr(data, &addr);
if(result)
return NULL;
}
-
- /* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if(!entry_id)
- return NULL;
- entry_len = strlen(entry_id);
+#endif
/* Create a new cache entry */
dns = calloc(1, sizeof(struct Curl_dns_entry));
if(!dns) {
- free(entry_id);
return NULL;
}
+ /* Create an entry id, based upon the hostname and port */
+ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
+ entry_len = strlen(entry_id);
+
dns->inuse = 1; /* the cache has the first reference */
dns->addr = addr; /* this is the address(es) */
time(&dns->timestamp);
@@ -484,16 +453,11 @@ Curl_cache_addr(struct Curl_easy *data,
(void *)dns);
if(!dns2) {
free(dns);
- free(entry_id);
return NULL;
}
dns = dns2;
dns->inuse++; /* mark entry as in-use */
-
- /* free the allocated entry_id */
- free(entry_id);
-
return dns;
}
@@ -521,6 +485,7 @@ Curl_cache_addr(struct Curl_easy *data,
int Curl_resolv(struct connectdata *conn,
const char *hostname,
int port,
+ bool allowDOH,
struct Curl_dns_entry **entry)
{
struct Curl_dns_entry *dns = NULL;
@@ -548,7 +513,7 @@ int Curl_resolv(struct connectdata *conn,
/* The entry was not in the cache. Resolve it to IP address */
Curl_addrinfo *addr;
- int respwait;
+ int respwait = 0;
/* Check what IP specifics the app has requested and if we can provide it.
* If not, bail out. */
@@ -566,7 +531,7 @@ int Curl_resolv(struct connectdata *conn,
return CURLRESOLV_ERROR;
}
- if(data->set.doh) {
+ if(allowDOH && data->set.doh) {
addr = Curl_doh(conn, hostname, port, &respwait);
}
else {
@@ -692,7 +657,7 @@ int Curl_resolv_timeout(struct connectdata *conn,
if(!timeout)
/* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
- return Curl_resolv(conn, hostname, port, entry);
+ return Curl_resolv(conn, hostname, port, TRUE, entry);
if(timeout < 1000) {
/* The alarm() function only provides integer second resolution, so if
@@ -754,7 +719,7 @@ int 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, entry);
+ rc = Curl_resolv(conn, hostname, port, TRUE, entry);
#ifdef USE_ALARM_TIMEOUT
clean_up:
@@ -872,11 +837,14 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
char hostname[256];
int port = 0;
+ /* Default is no wildcard found */
+ data->change.wildcard_resolve = false;
+
for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
+ char entry_id[MAX_HOSTCACHE_LEN];
if(!hostp->data)
continue;
if(hostp->data[0] == '-') {
- char *entry_id;
size_t entry_len;
if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
@@ -886,12 +854,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
/* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if(!entry_id) {
- return CURLE_OUT_OF_MEMORY;
- }
-
+ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
entry_len = strlen(entry_id);
if(data->share)
@@ -902,14 +865,10 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-
- /* free the allocated entry_id again */
- free(entry_id);
}
else {
struct Curl_dns_entry *dns;
Curl_addrinfo *head = NULL, *tail = NULL;
- char *entry_id;
size_t entry_len;
char address[64];
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -1005,12 +964,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
/* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if(!entry_id) {
- Curl_freeaddrinfo(head);
- return CURLE_OUT_OF_MEMORY;
- }
+ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
entry_len = strlen(entry_id);
if(data->share)
@@ -1031,8 +985,6 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
}
- /* free the allocated entry_id again */
- free(entry_id);
/* put this new host in the cache */
dns = Curl_cache_addr(data, head, hostname, port);
@@ -1052,6 +1004,13 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
infof(data, "Added %s:%d:%s to DNS cache\n",
hostname, port, addresses);
+
+ /* Wildcard hostname */
+ if(hostname[0] == '*' && hostname[1] == '\0') {
+ infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
+ hostname, port);
+ data->change.wildcard_resolve = true;
+ }
}
}
data->change.resolve = NULL; /* dealt with now */
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index 29fd1ef7c..9dc0d5a17 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -83,8 +83,11 @@ struct Curl_dns_entry {
#define CURLRESOLV_ERROR -1
#define CURLRESOLV_RESOLVED 0
#define CURLRESOLV_PENDING 1
-int Curl_resolv(struct connectdata *conn, const char *hostname,
- int port, struct Curl_dns_entry **dnsentry);
+int Curl_resolv(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ bool allowDOH,
+ struct Curl_dns_entry **dnsentry);
int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
int port, struct Curl_dns_entry **dnsentry,
time_t timeoutms);
@@ -179,16 +182,6 @@ Curl_fetch_addr(struct connectdata *conn,
int port);
/*
- * Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
- * struct by re-linking its linked list.
- *
- * The addr argument should be the address of a pointer to the head node of a
- * `Curl_addrinfo` list and it will be modified to point to the new head after
- * shuffling.
- */
-CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr);
-
-/*
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
*
* Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c
index 9d6f115ae..e6ba710d8 100644
--- a/Utilities/cmcurl/lib/hostip4.c
+++ b/Utilities/cmcurl/lib/hostip4.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -145,7 +145,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
if(port) {
- snprintf(sbuf, sizeof(sbuf), "%d", port);
+ msnprintf(sbuf, sizeof(sbuf), "%d", port);
sbufptr = sbuf;
}
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
index 3bf47b467..5511f1aab 100644
--- a/Utilities/cmcurl/lib/hostip6.c
+++ b/Utilities/cmcurl/lib/hostip6.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -101,14 +101,16 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
{
printf("dump_addrinfo:\n");
for(; ai; ai = ai->ai_next) {
- char buf[INET6_ADDRSTRLEN];
-
+ char buf[INET6_ADDRSTRLEN];
printf(" fam %2d, CNAME %s, ",
ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
if(Curl_printable_address(ai, buf, sizeof(buf)))
printf("%s\n", buf);
- else
- printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
+ else {
+ char buffer[STRERROR_LEN];
+ printf("failed; %s\n",
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+ }
}
}
#else
@@ -178,7 +180,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
#endif
if(port) {
- snprintf(sbuf, sizeof(sbuf), "%d", port);
+ msnprintf(sbuf, sizeof(sbuf), "%d", port);
sbufptr = sbuf;
}
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 46ac15a6e..338c59a22 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -73,10 +73,10 @@
#include "http_proxy.h"
#include "warnless.h"
#include "non-ascii.h"
-#include "pipeline.h"
#include "http2.h"
#include "connect.h"
#include "strdup.h"
+#include "altsvc.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -92,7 +92,9 @@ static int http_getsock_do(struct connectdata *conn,
int numsocks);
static int http_should_fail(struct connectdata *conn);
+#ifndef CURL_DISABLE_PROXY
static CURLcode add_haproxy_protocol_header(struct connectdata *conn);
+#endif
#ifdef USE_SSL
static CURLcode https_connecting(struct connectdata *conn, bool *done);
@@ -102,13 +104,14 @@ static int https_getsock(struct connectdata *conn,
#else
#define https_connecting(x,y) CURLE_COULDNT_CONNECT
#endif
+static CURLcode http_setup_conn(struct connectdata *conn);
/*
* HTTP handler interface.
*/
const struct Curl_handler Curl_handler_http = {
"HTTP", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
+ http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@@ -133,7 +136,7 @@ const struct Curl_handler Curl_handler_http = {
*/
const struct Curl_handler Curl_handler_https = {
"HTTPS", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
+ http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@@ -153,7 +156,7 @@ const struct Curl_handler Curl_handler_https = {
};
#endif
-CURLcode Curl_http_setup_conn(struct connectdata *conn)
+static CURLcode http_setup_conn(struct connectdata *conn)
{
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
@@ -175,7 +178,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
return CURLE_OK;
}
-
+#ifndef CURL_DISABLE_PROXY
/*
* checkProxyHeaders() checks the linked list of custom proxy headers
* if proxy headers are not available, then it will lookup into http header
@@ -202,6 +205,10 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
return NULL;
}
+#else
+/* disabled */
+#define Curl_checkProxyheaders(x,y) NULL
+#endif
/*
* Strip off leading and trailing whitespace from the value in the
@@ -256,6 +263,7 @@ char *Curl_copy_header_value(const char *header)
return value;
}
+#ifndef CURL_DISABLE_HTTP_AUTH
/*
* http_output_basic() sets up an Authorization: header (or the proxy version)
* for HTTP Basic authentication.
@@ -337,6 +345,8 @@ static CURLcode http_output_bearer(struct connectdata *conn)
return result;
}
+#endif
+
/* pickoneauth() selects the most favourable authentication method from the
* ones available and the ones we want.
*
@@ -415,7 +425,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
break;
}
- bytessent = http->writebytecount;
+ bytessent = data->req.writebytecount;
if(conn->bits.authneg) {
/* This is a state where we are known to be negotiating and we don't send
@@ -456,8 +466,8 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
(data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
(data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
if(((expectsend - bytessent) < 2000) ||
- (conn->ntlm.state != NTLMSTATE_NONE) ||
- (conn->proxyntlm.state != NTLMSTATE_NONE)) {
+ (conn->http_ntlm_state != NTLMSTATE_NONE) ||
+ (conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
/* The NTLM-negotiation has started *OR* there is just a little (<2K)
data left to send, keep on sending. */
@@ -479,8 +489,36 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
(curl_off_t)(expectsend - bytessent));
}
#endif
+#if defined(USE_SPNEGO)
+ /* There is still data left to send */
+ if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) ||
+ (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) {
+ if(((expectsend - bytessent) < 2000) ||
+ (conn->http_negotiate_state != GSS_AUTHNONE) ||
+ (conn->proxy_negotiate_state != GSS_AUTHNONE)) {
+ /* The NEGOTIATE-negotiation has started *OR*
+ there is just a little (<2K) data left to send, keep on sending. */
+
+ /* rewind data when completely done sending! */
+ if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
+ conn->bits.rewindaftersend = TRUE;
+ infof(data, "Rewind stream after send\n");
+ }
+
+ return CURLE_OK;
+ }
- /* This is not NTLM or many bytes left to send: close */
+ if(conn->bits.close)
+ /* this is already marked to get closed */
+ return CURLE_OK;
+
+ infof(data, "NEGOTIATE send, close instead of sending %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ (curl_off_t)(expectsend - bytessent));
+ }
+#endif
+
+ /* This is not NEGOTIATE/NTLM or many bytes left to send: close */
streamclose(conn, "Mid-auth HTTP and much data left to send");
data->req.size = 0; /* don't download any more than 0 bytes */
@@ -526,6 +564,12 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
pickhost = pickoneauth(&data->state.authhost, authmask);
if(!pickhost)
data->state.authproblem = TRUE;
+ if(data->state.authhost.picked == CURLAUTH_NTLM &&
+ 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;
+ }
}
if(conn->bits.proxy_user_passwd &&
((data->req.httpcode == 407) ||
@@ -576,6 +620,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
return result;
}
+#ifndef CURL_DISABLE_HTTP_AUTH
/*
* Output the correct authentication header depending on the auth type
* and whether or not it is to a proxy.
@@ -592,10 +637,6 @@ output_auth_headers(struct connectdata *conn,
#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO)
struct Curl_easy *data = conn->data;
#endif
-#ifdef USE_SPNEGO
- struct negotiatedata *negdata = proxy ?
- &data->state.proxyneg : &data->state.negotiate;
-#endif
#ifdef CURL_DISABLE_CRYPTO_AUTH
(void)request;
@@ -603,15 +644,11 @@ output_auth_headers(struct connectdata *conn,
#endif
#ifdef USE_SPNEGO
- negdata->state = GSS_AUTHNONE;
- if((authstatus->picked == CURLAUTH_NEGOTIATE) &&
- negdata->context && !GSS_ERROR(negdata->status)) {
+ if((authstatus->picked == CURLAUTH_NEGOTIATE)) {
auth = "Negotiate";
result = Curl_output_negotiate(conn, proxy);
if(result)
return result;
- authstatus->done = TRUE;
- negdata->state = GSS_AUTHSENT;
}
else
#endif
@@ -697,7 +734,7 @@ output_auth_headers(struct connectdata *conn,
*
* @param conn all information about the current connection
* @param request pointer to the request keyword
- * @param path pointer to the requested path
+ * @param path pointer to the requested path; should include query part
* @param proxytunnel boolean if this is the request setting up a "proxy
* tunnel"
*
@@ -744,7 +781,7 @@ Curl_http_output_auth(struct connectdata *conn,
#ifndef CURL_DISABLE_PROXY
/* Send proxy authentication header if needed */
if(conn->bits.httpproxy &&
- (conn->bits.tunnel_proxy == proxytunnel)) {
+ (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
result = output_auth_headers(conn, authproxy, request, path, TRUE);
if(result)
return result;
@@ -772,6 +809,22 @@ Curl_http_output_auth(struct connectdata *conn,
return result;
}
+#else
+/* when disabled */
+CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ const char *request,
+ const char *path,
+ bool proxytunnel)
+{
+ (void)conn;
+ (void)request;
+ (void)path;
+ (void)proxytunnel;
+ return CURLE_OK;
+}
+#endif
+
/*
* Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
* headers. They are dealt with both in the transfer.c main loop and in the
@@ -787,8 +840,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
struct Curl_easy *data = conn->data;
#ifdef USE_SPNEGO
- struct negotiatedata *negdata = proxy?
- &data->state.proxyneg:&data->state.negotiate;
+ curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
+ &conn->http_negotiate_state;
#endif
unsigned long *availp;
struct auth *authp;
@@ -827,21 +880,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
authp->avail |= CURLAUTH_NEGOTIATE;
if(authp->picked == CURLAUTH_NEGOTIATE) {
- if(negdata->state == GSS_AUTHSENT ||
- negdata->state == GSS_AUTHNONE) {
- CURLcode result = Curl_input_negotiate(conn, proxy, auth);
- if(!result) {
- DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->change.url);
- if(!data->req.newurl)
- return CURLE_OUT_OF_MEMORY;
- data->state.authproblem = FALSE;
- /* we received a GSS auth token and we dealt with it fine */
- negdata->state = GSS_AUTHRECV;
- }
- else
- data->state.authproblem = TRUE;
+ CURLcode result = Curl_input_negotiate(conn, proxy, auth);
+ if(!result) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->change.url);
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authproblem = FALSE;
+ /* we received a GSS auth token and we dealt with it fine */
+ *negstate = GSS_AUTHRECV;
}
+ else
+ data->state.authproblem = TRUE;
}
}
}
@@ -869,19 +919,10 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
*availp |= CURLAUTH_NTLM_WB;
authp->avail |= CURLAUTH_NTLM_WB;
- /* Get the challenge-message which will be passed to
- * ntlm_auth for generating the type 3 message later */
- while(*auth && ISSPACE(*auth))
- auth++;
- if(checkprefix("NTLM", auth)) {
- auth += strlen("NTLM");
- while(*auth && ISSPACE(*auth))
- auth++;
- if(*auth) {
- conn->challenge_header = strdup(auth);
- if(!conn->challenge_header)
- return CURLE_OUT_OF_MEMORY;
- }
+ result = Curl_input_ntlm_wb(conn, proxy, auth);
+ if(result) {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
}
}
#endif
@@ -1111,14 +1152,13 @@ void Curl_add_buffer_free(Curl_send_buffer **inp)
CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
- /* add the number of sent bytes to this
- counter */
- long *bytes_written,
+ /* add the number of sent bytes to this
+ counter */
+ curl_off_t *bytes_written,
- /* how much of the buffer contains body data */
+ /* how much of the buffer contains body data */
size_t included_body_bytes,
int socketindex)
-
{
ssize_t amount;
CURLcode result;
@@ -1214,7 +1254,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
if(http) {
/* if we sent a piece of the body here, up the byte counter for it
accordingly */
- http->writebytecount += bodylen;
+ data->req.writebytecount += bodylen;
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
if((size_t)amount != size) {
/* The whole request could not be sent in one system call. We must
@@ -1255,7 +1296,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
This needs FIXing.
*/
return CURLE_SEND_ERROR;
- Curl_pipeline_leave_write(conn);
}
}
Curl_add_buffer_free(&in);
@@ -1432,12 +1472,14 @@ 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;
+#ifndef CURL_DISABLE_PROXY
if(conn->data->set.haproxyprotocol) {
/* add HAProxy PROXY protocol header */
result = add_haproxy_protocol_header(conn);
if(result)
return result;
}
+#endif
if(conn->given->protocol & CURLPROTO_HTTPS) {
/* perform SSL initialization */
@@ -1464,6 +1506,7 @@ static int http_getsock_do(struct connectdata *conn,
return GETSOCK_WRITESOCK(0);
}
+#ifndef CURL_DISABLE_PROXY
static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
{
char proxy_header[128];
@@ -1479,14 +1522,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
strcpy(tcp_version, "TCP4");
}
- snprintf(proxy_header,
- 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);
+ msnprintf(proxy_header,
+ 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);
req_buffer = Curl_add_buffer_init();
if(!req_buffer)
@@ -1504,6 +1547,7 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
return result;
}
+#endif
#ifdef USE_SSL
static CURLcode https_connecting(struct connectdata *conn, bool *done)
@@ -1547,20 +1591,6 @@ CURLcode Curl_http_done(struct connectdata *conn,
Curl_unencode_cleanup(conn);
-#ifdef USE_SPNEGO
- if(data->state.proxyneg.state == GSS_AUTHSENT ||
- data->state.negotiate.state == GSS_AUTHSENT) {
- /* add forbid re-use if http-code != 401/407 as a WA only needed for
- * 401/407 that signal auth failure (empty) otherwise state will be RECV
- * with current code.
- * Do not close CONNECT_ONLY connections. */
- if((data->req.httpcode != 401) && (data->req.httpcode != 407) &&
- !data->set.connect_only)
- streamclose(conn, "Negotiate transfer completed");
- Curl_cleanup_negotiate(data);
- }
-#endif
-
/* set the proper values (possibly modified on POST) */
conn->seek_func = data->set.seek_func; /* restore */
conn->seek_client = data->set.seek_client; /* restore */
@@ -1576,16 +1606,6 @@ CURLcode Curl_http_done(struct connectdata *conn,
Curl_mime_cleanpart(&http->form);
- switch(data->set.httpreq) {
- case HTTPREQ_PUT:
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- data->req.bytecount = http->readbytecount + http->writebytecount;
- break;
- default:
- break;
- }
-
if(status)
return status;
@@ -1593,7 +1613,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
entire operation is complete */
!conn->bits.retry &&
!data->set.connect_only &&
- (http->readbytecount +
+ (data->req.bytecount +
data->req.headerbytecount -
data->req.deductheadercount) <= 0) {
/* If this connection isn't simply closed to be retried, AND nothing was
@@ -1676,6 +1696,50 @@ enum proxy_use {
HEADER_CONNECT /* sending CONNECT to a proxy */
};
+/* used to compile the provided trailers into one buffer
+ will return an error code if one of the headers is
+ not formatted correctly */
+CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
+ Curl_send_buffer *buffer,
+ struct Curl_easy *handle)
+{
+ char *ptr = NULL;
+ CURLcode result = CURLE_OK;
+ const char *endofline_native = NULL;
+ const char *endofline_network = NULL;
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (handle->set.prefer_ascii) ||
+#endif
+ (handle->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+
+ while(trailers) {
+ /* only add correctly formatted trailers */
+ ptr = strchr(trailers->data, ':');
+ if(ptr && *(ptr + 1) == ' ') {
+ result = Curl_add_bufferf(&buffer, "%s%s", trailers->data,
+ endofline_native);
+ if(result)
+ return result;
+ }
+ else
+ infof(handle, "Malformatted trailing header ! Skipping trailer.");
+ trailers = trailers->next;
+ }
+ result = Curl_add_buffer(&buffer, endofline_network,
+ strlen(endofline_network));
+ return result;
+}
+
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
Curl_send_buffer *req_buffer)
@@ -1737,9 +1801,16 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
}
else {
if(*(--ptr) == ';') {
- /* send no-value custom header if terminated by semicolon */
- *ptr = ':';
- semicolonp = ptr;
+ /* copy the source */
+ semicolonp = strdup(headers->data);
+ if(!semicolonp) {
+ Curl_add_buffer_free(&req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* put a colon where the semicolon is */
+ semicolonp[ptr - headers->data] = ':';
+ /* point at the colon */
+ optr = &semicolonp [ptr - headers->data];
}
}
ptr = optr;
@@ -1755,35 +1826,37 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
if(*ptr || semicolonp) {
/* only send this if the contents was non-blank or done special */
CURLcode result = CURLE_OK;
+ char *compare = semicolonp ? semicolonp : headers->data;
if(conn->allocptr.host &&
/* a Host: header was sent already, don't pass on any custom Host:
header as that will produce *two* in the same request! */
- checkprefix("Host:", headers->data))
+ checkprefix("Host:", compare))
;
else if(data->set.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
- checkprefix("Content-Type:", headers->data))
+ checkprefix("Content-Type:", compare))
;
else if(data->set.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
- checkprefix("Content-Type:", headers->data))
+ checkprefix("Content-Type:", compare))
;
else if(conn->bits.authneg &&
/* while doing auth neg, don't allow the custom length since
we will force length zero then */
- checkprefix("Content-Length:", headers->data))
+ checkprefix("Content-Length:", compare))
;
else if(conn->allocptr.te &&
/* when asking for Transfer-Encoding, don't pass on a custom
Connection: */
- checkprefix("Connection:", headers->data))
+ checkprefix("Connection:", compare))
;
else if((conn->httpversion == 20) &&
- checkprefix("Transfer-Encoding:", headers->data))
+ checkprefix("Transfer-Encoding:", compare))
/* HTTP/2 doesn't support chunked requests */
;
- else if(checkprefix("Authorization:", headers->data) &&
+ else if((checkprefix("Authorization:", compare) ||
+ checkprefix("Cookie:", compare)) &&
/* be careful of sending this potentially sensitive header to
other hosts */
(data->state.this_is_a_follow &&
@@ -1792,10 +1865,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
!strcasecompare(data->state.first_host, conn->host.name)))
;
else {
- result = Curl_add_bufferf(&req_buffer, "%s\r\n", headers->data);
+ result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare);
}
if(semicolonp)
- *semicolonp = ';'; /* put back the semicolon */
+ free(semicolonp);
if(result)
return result;
}
@@ -1807,6 +1880,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
return CURLE_OK;
}
+#ifndef CURL_DISABLE_PARSEDATE
CURLcode Curl_add_timecondition(struct Curl_easy *data,
Curl_send_buffer *req_buffer)
{
@@ -1850,21 +1924,31 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
*/
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- snprintf(datestr, sizeof(datestr),
- "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- condp,
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
+ msnprintf(datestr, sizeof(datestr),
+ "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ condp,
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr));
return result;
}
+#else
+/* disabled */
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+ Curl_send_buffer *req_buffer)
+{
+ (void)data;
+ (void)req_buffer;
+ return CURLE_OK;
+}
+#endif
/*
* Curl_http() gets called from the generic multi_do() function when a HTTP
@@ -1916,6 +2000,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
#ifdef USE_NGHTTP2
if(conn->data->set.httpversion ==
CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ 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;
+ }
+
DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
conn->httpversion = 20;
@@ -1947,7 +2038,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.first_remote_port = conn->remote_port;
}
- http->writebytecount = http->readbytecount = 0;
if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
data->set.upload) {
@@ -1995,11 +2085,21 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
/* setup the authentication headers */
- result = Curl_http_output_auth(conn, request, path, FALSE);
- if(result)
- return result;
+ {
+ 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.authproxy.multipass) &&
+ 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
@@ -2084,6 +2184,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sendit = NULL;
}
+#ifndef CURL_DISABLE_MIME
if(http->sendit) {
const char *cthdr = Curl_checkheaders(conn, "Content-Type");
@@ -2108,6 +2209,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
http->postsize = Curl_mime_size(http->sendit);
}
+#endif
ptr = Curl_checkheaders(conn, "Transfer-Encoding");
if(ptr) {
@@ -2293,8 +2395,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(!*data->state.up.path && path[strlen(path) - 1] != '/') {
*p++ = '/';
}
- snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
- data->set.prefer_ascii ? 'a' : 'i');
+ msnprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
+ data->set.prefer_ascii ? 'a' : 'i');
}
}
if(conn->bits.user_passwd && !conn->bits.userpwd_in_url)
@@ -2635,9 +2737,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
failf(data, "Failed sending PUT request");
else
/* prepare for transfer */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount, postsize?FIRSTSOCKET:-1,
- postsize?&http->writebytecount:NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ postsize?FIRSTSOCKET:-1);
if(result)
return result;
break;
@@ -2657,12 +2758,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
failf(data, "Failed sending POST request");
else
/* setup variables for the upcoming transfer */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
- -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
break;
}
- postsize = http->postsize;
+ data->state.infilesize = postsize = 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
@@ -2678,6 +2778,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
+#ifndef CURL_DISABLE_MIME
/* Output mime-generated headers. */
{
struct curl_slist *hdr;
@@ -2688,6 +2789,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
}
+#endif
/* 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
@@ -2726,9 +2828,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
failf(data, "Failed sending POST request");
else
/* prepare for transfer */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount, postsize?FIRSTSOCKET:-1,
- postsize?&http->writebytecount:NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ postsize?FIRSTSOCKET:-1);
if(result)
return result;
@@ -2882,9 +2983,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(result)
failf(data, "Failed sending HTTP POST request");
else
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount, http->postdata?FIRSTSOCKET:-1,
- http->postdata?&http->writebytecount:NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ http->postdata?FIRSTSOCKET:-1);
break;
default:
@@ -2900,33 +3000,30 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
failf(data, "Failed sending HTTP request");
else
/* HTTP GET/HEAD download: */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
- http->postdata?FIRSTSOCKET:-1,
- http->postdata?&http->writebytecount:NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ http->postdata?FIRSTSOCKET:-1);
}
if(result)
return result;
- if(http->writebytecount) {
+ if(data->req.writebytecount) {
/* if a request-body has been sent off, we make sure this progress is noted
properly */
- Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
- if(http->writebytecount >= postsize) {
+ if(data->req.writebytecount >= 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",
- http->writebytecount, postsize);
+ data->req.writebytecount, postsize);
data->req.upload_done = TRUE;
data->req.keepon &= ~KEEP_SEND; /* we're done writing */
data->req.exp100 = EXP100_SEND_DATA; /* already sent */
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
}
- else
- data->req.writebytecount = http->writebytecount;
}
if((conn->httpversion == 20) && data->req.upload_chunky)
@@ -3161,6 +3258,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
k->header = FALSE;
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");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
break;
}
}
@@ -3194,6 +3295,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(st == STATUS_BAD) {
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");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
k->header = FALSE;
if(*nread)
/* since there's more, this is a partial bad header */
@@ -3306,14 +3411,31 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
#if defined(USE_NTLM)
if(conn->bits.close &&
(((data->req.httpcode == 401) &&
- (conn->ntlm.state == NTLMSTATE_TYPE2)) ||
+ (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
((data->req.httpcode == 407) &&
- (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) {
+ (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
data->state.authproblem = TRUE;
}
#endif
-
+#if defined(USE_SPNEGO)
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->http_negotiate_state == GSS_AUTHRECV)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+ data->state.authproblem = TRUE;
+ }
+ if((conn->http_negotiate_state == GSS_AUTHDONE) &&
+ (data->req.httpcode != 401)) {
+ conn->http_negotiate_state = GSS_AUTHSUCC;
+ }
+ if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
+ (data->req.httpcode != 407)) {
+ conn->proxy_negotiate_state = GSS_AUTHSUCC;
+ }
+#endif
/*
* When all the headers have been parsed, see if we should give
* up and return an error.
@@ -3549,6 +3671,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(conn->httpversion != 20)
infof(data, "Lying server, not serving HTTP/2\n");
}
+ if(conn->httpversion < 20) {
+ conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
+ infof(data, "Mark bundle as not supporting multiuse\n");
+ }
}
else if(!nc) {
/* this is the real world, not a Nirvana
@@ -3586,7 +3712,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
}
else {
- /* TODO: do we care about the other cases here? */
nc = 0;
}
}
@@ -3639,26 +3764,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
else if(conn->httpversion >= 11 &&
!conn->bits.close) {
- /* If HTTP version is >= 1.1 and connection is persistent
- server supports pipelining. */
+ /* If HTTP version is >= 1.1 and connection is persistent */
DEBUGF(infof(data,
- "HTTP 1.1 or later with persistent connection, "
- "pipelining supported\n"));
- /* Activate pipelining if needed */
- if(conn->bundle) {
- if(!Curl_pipeline_site_blacklisted(data, conn))
- conn->bundle->multiuse = BUNDLE_PIPELINING;
- }
+ "HTTP 1.1 or later with persistent connection\n"));
}
switch(k->httpcode) {
- 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. */
- /* FALLTHROUGH */
case 304:
/* (quote from RFC2616, section 10.3.5): The 304 response
* MUST NOT contain a message-body, and thus is always
@@ -3666,6 +3777,13 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* 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->ignorecl = TRUE; /* ignore Content-Length headers */
@@ -3733,19 +3851,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
data->info.contenttype = contenttype;
}
}
- else if(checkprefix("Server:", k->p)) {
- if(conn->httpversion < 20) {
- /* only do this for non-h2 servers */
- char *server_name = Curl_copy_header_value(k->p);
-
- /* Turn off pipelining if the server version is blacklisted */
- if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) {
- if(Curl_pipeline_server_blacklisted(data, server_name))
- conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
- }
- free(server_name);
- }
- }
else if((conn->httpversion == 10) &&
conn->bits.httpproxy &&
Curl_compareheader(k->p,
@@ -3859,7 +3964,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
here, or else use real peer host name. */
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:conn->host.name,
- data->state.up.path);
+ data->state.up.path,
+ (conn->handler->protocol&CURLPROTO_HTTPS)?
+ TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
@@ -3888,6 +3995,22 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(result)
return result;
}
+ #ifdef USE_SPNEGO
+ else if(checkprefix("Persistent-Auth", k->p)) {
+ struct negotiatedata *negdata = &conn->negotiate;
+ struct auth *authp = &data->state.authhost;
+ if(authp->picked == CURLAUTH_NEGOTIATE) {
+ char *persistentauth = Curl_copy_header_value(k->p);
+ if(!persistentauth)
+ return CURLE_OUT_OF_MEMORY;
+ negdata->noauthpersist = checkprefix("false", persistentauth);
+ 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:", k->p) &&
!data->req.location) {
@@ -3915,6 +4038,27 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
}
+#ifdef USE_ALTSVC
+ /* If enabled, the header is incoming and this is over HTTPS */
+ else if(data->asi && checkprefix("Alt-Svc:", k->p) &&
+ ((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,
+ &k->p[ 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, k->p);
if(result)
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index 21fa701ab..a59fe7af0 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -65,7 +65,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
size_t size) WARN_UNUSED_RESULT;
CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
- long *bytes_written,
+ curl_off_t *bytes_written,
size_t included_body_bytes,
int socketindex);
@@ -74,6 +74,9 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
Curl_send_buffer *req_buffer);
+CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
+ Curl_send_buffer *buffer,
+ struct Curl_easy *handle);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done);
@@ -136,8 +139,6 @@ struct HTTP {
const char *p_pragma; /* Pragma: string */
const char *p_accept; /* Accept: string */
- curl_off_t readbytecount;
- curl_off_t writebytecount;
/* For FORM posting */
curl_mimepart form;
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index 0c5f6db0b..8e7bc217e 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -111,8 +111,6 @@ static int http2_perform_getsock(const struct connectdata *conn,
int bitmap = GETSOCK_BLANK;
(void)numsocks;
- /* TODO We should check underlying socket state if it is SSL socket
- because of renegotiation. */
sock[0] = conn->sock[FIRSTSOCKET];
/* in a HTTP/2 connection we can basically always get a frame so we should
@@ -350,14 +348,14 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
int Curl_http2_ver(char *p, size_t len)
{
nghttp2_info *h2 = nghttp2_version(0);
- return snprintf(p, len, " nghttp2/%s", h2->version_str);
+ return msnprintf(p, len, " nghttp2/%s", h2->version_str);
}
/* HTTP/2 error code to name based on the Error Code Registry.
https://tools.ietf.org/html/rfc7540#page-77
nghttp2_error_code enums are identical.
*/
-const char *Curl_http2_strerror(uint32_t err)
+static const char *http2_strerror(uint32_t err)
{
#ifndef NGHTTP2_HAS_HTTP2_STRERROR
const char *str[] = {
@@ -618,6 +616,18 @@ static int push_promise(struct Curl_easy *data,
return rv;
}
+/*
+ * multi_connchanged() is called to tell that there is a connection in
+ * this multi handle that has changed state (multiplexing become possible, the
+ * number of allowed streams changed or similar), and a subsequent use of this
+ * multi handle should move CONNECT_PEND handles back to CONNECT to have them
+ * retry.
+ */
+static void multi_connchanged(struct Curl_multi *multi)
+{
+ multi->recheckstate = TRUE;
+}
+
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
void *userp)
{
@@ -650,7 +660,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
infof(conn->data,
"Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n",
httpc->settings.max_concurrent_streams);
- Curl_multi_connchanged(conn->data->multi);
+ multi_connchanged(conn->data->multi);
}
}
return 0;
@@ -800,7 +810,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
", stream %u\n",
len - nread, stream_id));
- data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+ data_s->conn->proto.httpc.pause_stream_id = stream_id;
return NGHTTP2_ERR_PAUSE;
}
@@ -808,7 +818,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
/* pause execution of nghttp2 if we received data for another handle
in order to process them first. */
if(conn->data != data_s) {
- data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+ data_s->conn->proto.httpc.pause_stream_id = stream_id;
return NGHTTP2_ERR_PAUSE;
}
@@ -837,7 +847,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
return 0;
}
H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
- Curl_http2_strerror(error_code), error_code, stream_id));
+ http2_strerror(error_code), error_code, stream_id));
stream = data_s->req.protop;
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -854,6 +864,10 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream_id);
DEBUGASSERT(0);
}
+ if(stream_id == httpc->pause_stream_id) {
+ H2BUGF(infof(data_s, "Stopped the pause stream!\n"));
+ httpc->pause_stream_id = 0;
+ }
H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
stream->stream_id = 0; /* cleared */
}
@@ -953,6 +967,28 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
char *h;
+ if(!strcmp(":authority", (const char *)name)) {
+ /* pseudo headers are lower case */
+ int rc = 0;
+ char *check = aprintf("%s:%d", conn->host.name, conn->remote_port);
+ if(!check)
+ /* no memory */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ if(!Curl_strcasecompare(check, (const char *)value)) {
+ /* This is push is not for the same authority that was asked for in
+ * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
+ * PUSH_PROMISE for which the server is not authoritative as a stream
+ * error of type PROTOCOL_ERROR."
+ */
+ (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
+ stream_id, NGHTTP2_PROTOCOL_ERROR);
+ rc = NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ free(check);
+ if(rc)
+ return rc;
+ }
+
if(!stream->push_headers) {
stream->push_headers_alloc = 10;
stream->push_headers = malloc(stream->push_headers_alloc *
@@ -1193,7 +1229,7 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
/*
* Initialize nghttp2 for a Curl connection
*/
-CURLcode Curl_http2_init(struct connectdata *conn)
+static CURLcode http2_init(struct connectdata *conn)
{
if(!conn->proto.httpc.h2) {
int rc;
@@ -1427,7 +1463,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
}
else if(httpc->error_code != NGHTTP2_NO_ERROR) {
failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
- stream->stream_id, Curl_http2_strerror(httpc->error_code),
+ stream->stream_id, http2_strerror(httpc->error_code),
httpc->error_code);
*err = CURLE_HTTP2_STREAM;
return -1;
@@ -1809,9 +1845,9 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len, CURLcode *err)
{
/*
- * BIG TODO: Currently, we send request in this function, but this
- * function is also used to send request body. It would be nice to
- * add dedicated function for request.
+ * Currently, we send request in this function, but this function is also
+ * used to send request body. It would be nice to add dedicated function for
+ * request.
*/
int rv;
struct http_conn *httpc = &conn->proto.httpc;
@@ -2137,7 +2173,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
else
conn->handler = &Curl_handler_http2;
- result = Curl_http2_init(conn);
+ result = http2_init(conn);
if(result) {
Curl_add_buffer_free(&stream->header_recvbuf);
return result;
@@ -2159,7 +2195,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
- Curl_multi_connchanged(conn->data->multi);
+ multi_connchanged(conn->data->multi);
return CURLE_OK;
}
@@ -2367,6 +2403,14 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
Curl_http2_remove_child(data->set.stream_depends_on, data);
}
+/* Only call this function for a transfer that already got a HTTP/2
+ CURLE_HTTP2_STREAM error! */
+bool Curl_h2_http_1_1_error(struct connectdata *conn)
+{
+ struct http_conn *httpc = &conn->proto.httpc;
+ return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED);
+}
+
#else /* !USE_NGHTTP2 */
/* Satisfy external references even if http2 is not compiled in. */
diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h
index 4492ec211..db6217b11 100644
--- a/Utilities/cmcurl/lib/http2.h
+++ b/Utilities/cmcurl/lib/http2.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -59,8 +59,10 @@ CURLcode Curl_http2_add_child(struct Curl_easy *parent,
void Curl_http2_remove_child(struct Curl_easy *parent,
struct Curl_easy *child);
void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
+
+/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
+bool Curl_h2_http_1_1_error(struct connectdata *conn);
#else /* USE_NGHTTP2 */
-#define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
@@ -74,6 +76,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
#define Curl_http2_add_child(x, y, z)
#define Curl_http2_remove_child(x, y)
#define Curl_http2_cleanup_dependencies(x)
+#define Curl_h2_http_1_1_error(x) 0
#endif
#endif /* HEADER_CURL_HTTP2_H */
diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c
index e2d865b0a..9616c30ed 100644
--- a/Utilities/cmcurl/lib/http_digest.c
+++ b/Utilities/cmcurl/lib/http_digest.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -28,6 +28,7 @@
#include "strcase.h"
#include "vauth/vauth.h"
#include "http_digest.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -171,7 +172,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
return CURLE_OK;
}
-void Curl_digest_cleanup(struct Curl_easy *data)
+void Curl_http_auth_cleanup_digest(struct Curl_easy *data)
{
Curl_auth_digest_cleanup(&data->state.digest);
Curl_auth_digest_cleanup(&data->state.proxydigest);
diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h
index fd225c7c1..73410ae88 100644
--- a/Utilities/cmcurl/lib/http_digest.h
+++ b/Utilities/cmcurl/lib/http_digest.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -23,6 +23,8 @@
***************************************************************************/
#include "curl_setup.h"
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
/* this is for digest header input */
CURLcode Curl_input_digest(struct connectdata *conn,
bool proxy, const char *header);
@@ -33,10 +35,8 @@ CURLcode Curl_output_digest(struct connectdata *conn,
const unsigned char *request,
const unsigned char *uripath);
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-void Curl_digest_cleanup(struct Curl_easy *data);
-#else
-#define Curl_digest_cleanup(x) Curl_nop_stmt
-#endif
+void Curl_http_auth_cleanup_digest(struct Curl_easy *data);
+
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_CRYPTO_AUTH */
#endif /* HEADER_CURL_HTTP_DIGEST_H */
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c
index ddcd65b3b..c8f406444 100644
--- a/Utilities/cmcurl/lib/http_negotiate.c
+++ b/Utilities/cmcurl/lib/http_negotiate.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -49,6 +49,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
/* Point to the correct struct with this */
struct negotiatedata *neg_ctx;
+ curlnegotiate state;
if(proxy) {
userp = conn->http_proxy.user;
@@ -56,7 +57,8 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
host = conn->http_proxy.host.name;
- neg_ctx = &data->state.proxyneg;
+ neg_ctx = &conn->proxyneg;
+ state = conn->proxy_negotiate_state;
}
else {
userp = conn->user;
@@ -64,7 +66,8 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP";
host = conn->host.name;
- neg_ctx = &data->state.negotiate;
+ neg_ctx = &conn->negotiate;
+ state = conn->http_negotiate_state;
}
/* Not set means empty */
@@ -80,59 +83,138 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
header++;
len = strlen(header);
+ neg_ctx->havenegdata = len != 0;
if(!len) {
- /* Is this the first call in a new negotiation? */
- if(neg_ctx->context) {
- /* The server rejected our authentication and hasn't suppled any more
+ if(state == GSS_AUTHSUCC) {
+ infof(conn->data, "Negotiate auth restarted\n");
+ Curl_http_auth_cleanup_negotiate(conn);
+ }
+ else if(state != GSS_AUTHNONE) {
+ /* The server rejected our authentication and hasn't supplied any more
negotiation mechanisms */
+ Curl_http_auth_cleanup_negotiate(conn);
return CURLE_LOGIN_DENIED;
}
}
+ /* Supports SSL channel binding for Windows ISS extended protection */
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+ neg_ctx->sslContext = conn->sslContext;
+#endif
+
/* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
host, header, neg_ctx);
if(result)
- Curl_auth_spnego_cleanup(neg_ctx);
+ Curl_http_auth_cleanup_negotiate(conn);
return result;
}
CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
{
- struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg :
- &conn->data->state.negotiate;
+ struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
+ &conn->negotiate;
+ struct auth *authp = proxy ? &conn->data->state.authproxy :
+ &conn->data->state.authhost;
+ curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
+ &conn->http_negotiate_state;
char *base64 = NULL;
size_t len = 0;
char *userp;
CURLcode result;
- result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len);
- if(result)
- return result;
+ authp->done = FALSE;
- userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
- base64);
+ if(*state == GSS_AUTHRECV) {
+ if(neg_ctx->havenegdata) {
+ neg_ctx->havemultiplerequests = TRUE;
+ }
+ }
+ else if(*state == GSS_AUTHSUCC) {
+ if(!neg_ctx->havenoauthpersist) {
+ neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests;
+ }
+ }
- if(proxy) {
- Curl_safefree(conn->allocptr.proxyuserpwd);
- conn->allocptr.proxyuserpwd = userp;
+ if(neg_ctx->noauthpersist ||
+ (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
+
+ if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
+ infof(conn->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");
+ if(result == CURLE_LOGIN_DENIED) {
+ /* negotiate auth failed, let's continue unauthenticated to stay
+ * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
+ conn->data->state.authproblem = TRUE;
+ return CURLE_OK;
+ }
+ else if(result)
+ return result;
+ }
+
+ result = Curl_auth_create_spnego_message(conn->data,
+ neg_ctx, &base64, &len);
+ if(result)
+ return result;
+
+ userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
+ base64);
+
+ if(proxy) {
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = userp;
+ }
+ else {
+ Curl_safefree(conn->allocptr.userpwd);
+ conn->allocptr.userpwd = userp;
+ }
+
+ free(base64);
+
+ if(userp == NULL) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ *state = GSS_AUTHSENT;
+ #ifdef HAVE_GSSAPI
+ if(neg_ctx->status == GSS_S_COMPLETE ||
+ neg_ctx->status == GSS_S_CONTINUE_NEEDED) {
+ *state = GSS_AUTHDONE;
+ }
+ #else
+ #ifdef USE_WINDOWS_SSPI
+ if(neg_ctx->status == SEC_E_OK ||
+ neg_ctx->status == SEC_I_CONTINUE_NEEDED) {
+ *state = GSS_AUTHDONE;
+ }
+ #endif
+ #endif
}
- else {
- Curl_safefree(conn->allocptr.userpwd);
- conn->allocptr.userpwd = userp;
+
+ if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ authp->done = TRUE;
}
- free(base64);
+ neg_ctx->havenegdata = FALSE;
- return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+ return CURLE_OK;
}
-void Curl_cleanup_negotiate(struct Curl_easy *data)
+void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
{
- Curl_auth_spnego_cleanup(&data->state.negotiate);
- Curl_auth_spnego_cleanup(&data->state.proxyneg);
+ conn->http_negotiate_state = GSS_AUTHNONE;
+ conn->proxy_negotiate_state = GSS_AUTHNONE;
+
+ Curl_auth_cleanup_spnego(&conn->negotiate);
+ Curl_auth_cleanup_spnego(&conn->proxyneg);
}
#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h
index c64e54825..4f0ac1686 100644
--- a/Utilities/cmcurl/lib/http_negotiate.h
+++ b/Utilities/cmcurl/lib/http_negotiate.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,7 +22,7 @@
*
***************************************************************************/
-#ifdef USE_SPNEGO
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
/* this is for Negotiate header input */
CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
@@ -31,8 +31,8 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
/* this is for creating Negotiate header output */
CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
-void Curl_cleanup_negotiate(struct Curl_easy *data);
+void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
-#endif /* USE_SPNEGO */
+#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index a9b33f98e..e4a4fe05d 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -68,9 +68,11 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
{
/* point to the correct struct with this */
struct ntlmdata *ntlm;
+ curlntlm *state;
CURLcode result = CURLE_OK;
ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+ state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
if(checkprefix("NTLM", header)) {
header += strlen("NTLM");
@@ -83,25 +85,25 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
if(result)
return result;
- ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+ *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
}
else {
- if(ntlm->state == NTLMSTATE_LAST) {
+ if(*state == NTLMSTATE_LAST) {
infof(conn->data, "NTLM auth restarted\n");
- Curl_http_ntlm_cleanup(conn);
+ Curl_http_auth_cleanup_ntlm(conn);
}
- else if(ntlm->state == NTLMSTATE_TYPE3) {
+ else if(*state == NTLMSTATE_TYPE3) {
infof(conn->data, "NTLM handshake rejected\n");
- Curl_http_ntlm_cleanup(conn);
- ntlm->state = NTLMSTATE_NONE;
+ Curl_http_auth_cleanup_ntlm(conn);
+ *state = NTLMSTATE_NONE;
return CURLE_REMOTE_ACCESS_DENIED;
}
- else if(ntlm->state >= NTLMSTATE_TYPE1) {
+ else if(*state >= NTLMSTATE_TYPE1) {
infof(conn->data, "NTLM handshake failure (internal error)\n");
return CURLE_REMOTE_ACCESS_DENIED;
}
- ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+ *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
}
}
@@ -129,6 +131,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
/* point to the correct struct with this */
struct ntlmdata *ntlm;
+ curlntlm *state;
struct auth *authp;
DEBUGASSERT(conn);
@@ -147,6 +150,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
conn->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;
}
else {
@@ -157,6 +161,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
conn->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->done = FALSE;
@@ -175,9 +180,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
if(s_hSecDll == NULL)
return err;
}
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ ntlm->sslContext = conn->sslContext;
+#endif
#endif
- switch(ntlm->state) {
+ switch(*state) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
/* Create a type-1 message */
@@ -219,7 +227,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
- ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */
+ *state = NTLMSTATE_TYPE3; /* we send a type-3 */
authp->done = TRUE;
}
break;
@@ -227,7 +235,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
* don't send a header in future requests */
- ntlm->state = NTLMSTATE_LAST;
+ *state = NTLMSTATE_LAST;
/* FALLTHROUGH */
case NTLMSTATE_LAST:
Curl_safefree(*allocuserpwd);
@@ -238,13 +246,13 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
return CURLE_OK;
}
-void Curl_http_ntlm_cleanup(struct connectdata *conn)
+void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
{
- Curl_auth_ntlm_cleanup(&conn->ntlm);
- Curl_auth_ntlm_cleanup(&conn->proxyntlm);
+ Curl_auth_cleanup_ntlm(&conn->ntlm);
+ Curl_auth_cleanup_ntlm(&conn->proxyntlm);
#if defined(NTLM_WB_ENABLED)
- Curl_ntlm_wb_cleanup(conn);
+ Curl_http_auth_cleanup_ntlm_wb(conn);
#endif
}
diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h
index d186bbe37..003714dbd 100644
--- a/Utilities/cmcurl/lib/http_ntlm.h
+++ b/Utilities/cmcurl/lib/http_ntlm.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_NTLM_H
-#define HEADER_CURL_NTLM_H
+#ifndef HEADER_CURL_HTTP_NTLM_H
+#define HEADER_CURL_HTTP_NTLM_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -33,8 +33,8 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
/* this is for creating ntlm header output */
CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
-void Curl_http_ntlm_cleanup(struct connectdata *conn);
+void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
-#endif /* HEADER_CURL_NTLM_H */
+#endif /* HEADER_CURL_HTTP_NTLM_H */
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index 2e0d92edd..d7ed11761 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -643,7 +643,7 @@ static CURLcode CONNECT(struct connectdata *conn,
void Curl_connect_free(struct Curl_easy *data)
{
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
struct http_connect_state *s = conn->connect_state;
if(s) {
free(s);
diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c
index ce38ea117..d003de678 100644
--- a/Utilities/cmcurl/lib/if2ip.c
+++ b/Utilities/cmcurl/lib/if2ip.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -96,26 +96,8 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
#if defined(HAVE_GETIFADDRS)
-bool Curl_if_is_interface_name(const char *interf)
-{
- bool result = FALSE;
-
- struct ifaddrs *iface, *head;
-
- if(getifaddrs(&head) >= 0) {
- for(iface = head; iface != NULL; iface = iface->ifa_next) {
- if(strcasecompare(iface->ifa_name, interf)) {
- result = TRUE;
- break;
- }
- }
- freeifaddrs(head);
- }
- return result;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
- unsigned int remote_scope_id, const char *interf,
+ unsigned int local_scope_id, const char *interf,
char *buf, int buf_size)
{
struct ifaddrs *iface, *head;
@@ -127,7 +109,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
!defined(ENABLE_IPV6)
- (void) remote_scope_id;
+ (void) local_scope_id;
#endif
if(getifaddrs(&head) >= 0) {
@@ -141,7 +123,9 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
char ipstr[64];
#ifdef ENABLE_IPV6
if(af == AF_INET6) {
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
unsigned int scopeid = 0;
+#endif
unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
if(ifscope != remote_scope) {
@@ -161,15 +145,16 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
->sin6_scope_id;
/* If given, scope id should match. */
- if(remote_scope_id && scopeid != remote_scope_id) {
+ if(local_scope_id && scopeid != local_scope_id) {
if(res == IF2IP_NOT_FOUND)
res = IF2IP_AF_NOT_SUPPORTED;
continue;
}
-#endif
+
if(scopeid)
- snprintf(scope, sizeof(scope), "%%%u", scopeid);
+ msnprintf(scope, sizeof(scope), "%%%u", scopeid);
+#endif
}
else
#endif
@@ -177,7 +162,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
&((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
res = IF2IP_FOUND;
ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
- snprintf(buf, buf_size, "%s%s", ip, scope);
+ msnprintf(buf, buf_size, "%s%s", ip, scope);
break;
}
}
@@ -196,17 +181,8 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#elif defined(HAVE_IOCTL_SIOCGIFADDR)
-bool Curl_if_is_interface_name(const char *interf)
-{
- /* This is here just to support the old interfaces */
- char buf[256];
-
- return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
- IF2IP_NOT_FOUND) ? FALSE : TRUE;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
- unsigned int remote_scope_id, const char *interf,
+ unsigned int local_scope_id, const char *interf,
char *buf, int buf_size)
{
struct ifreq req;
@@ -216,7 +192,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
size_t len;
(void)remote_scope;
- (void)remote_scope_id;
+ (void)local_scope_id;
if(!interf || (af != AF_INET))
return IF2IP_NOT_FOUND;
@@ -251,20 +227,13 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#else
-bool Curl_if_is_interface_name(const char *interf)
-{
- (void) interf;
-
- return FALSE;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
- unsigned int remote_scope_id, const char *interf,
+ unsigned int local_scope_id, const char *interf,
char *buf, int buf_size)
{
(void) af;
(void) remote_scope;
- (void) remote_scope_id;
+ (void) local_scope_id;
(void) interf;
(void) buf;
(void) buf_size;
diff --git a/Utilities/cmcurl/lib/if2ip.h b/Utilities/cmcurl/lib/if2ip.h
index a90e66216..f193d4257 100644
--- a/Utilities/cmcurl/lib/if2ip.h
+++ b/Utilities/cmcurl/lib/if2ip.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -32,8 +32,6 @@
unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
-bool Curl_if_is_interface_name(const char *interf);
-
typedef enum {
IF2IP_NOT_FOUND = 0, /* Interface not found */
IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */
@@ -41,7 +39,7 @@ typedef enum {
} if2ip_result_t;
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
- unsigned int remote_scope_id, const char *interf,
+ unsigned int local_scope_id, const char *interf,
char *buf, int buf_size);
#ifdef __INTERIX
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index 3ef89097f..bdcc69c67 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -28,6 +28,7 @@
* RFC4959 IMAP Extension for SASL Initial Client Response
* RFC5092 IMAP URL Scheme
* RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
* Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
*
***************************************************************************/
@@ -316,7 +317,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
some e-mail servers ignore this and only send a single + instead. */
- if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
+ if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
(len >= 2 && !memcmp("+ ", line, 2)))) {
switch(imapc->state) {
/* States which are interested in continuation responses */
@@ -1042,7 +1043,7 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
line[len] = '\0';
}
else if(imapcode != IMAP_RESP_OK)
- result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
+ result = CURLE_QUOTE_ERROR;
else
/* End of DO phase */
state(conn, IMAP_STOP);
@@ -1114,7 +1115,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
if(imapcode != '*') {
Curl_pgrsSetDownloadSize(data, -1);
state(conn, IMAP_STOP);
- return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */
+ return CURLE_REMOTE_FILE_NOT_FOUND;
}
/* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
@@ -1177,11 +1178,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
if(data->req.bytecount == size)
/* The entire data is already transferred! */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
else {
/* IMAP download */
data->req.maxdownload = size;
- Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
}
}
else {
@@ -1231,7 +1232,7 @@ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* IMAP upload */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
state(conn, IMAP_STOP);
@@ -1362,19 +1363,20 @@ static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&imapc->pp, FALSE);
+ result = Curl_pp_statemach(&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 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);
+ result = Curl_pp_statemach(&imapc->pp, TRUE, disconnecting);
return result;
}
@@ -1490,14 +1492,9 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
state(conn, IMAP_APPEND_FINAL);
}
- /* Run the state-machine
-
- TODO: when the multi interface is used, this _really_ should be using
- the imap_multi_statemach function but we have no general support for
- non-blocking DONE operations!
- */
+ /* Run the state-machine */
if(!result)
- result = imap_block_statemach(conn);
+ result = imap_block_statemach(conn, FALSE);
}
/* Cleanup our per-request based variables */
@@ -1635,7 +1632,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
if(!imap_perform_logout(conn))
- (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */
+ (void)imap_block_statemach(conn, TRUE); /* ignore errors on LOGOUT */
/* Disconnect from the server */
Curl_pp_disconnect(&imapc->pp);
@@ -1659,7 +1656,7 @@ static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
if(imap->transfer != FTPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
return CURLE_OK;
}
@@ -1749,8 +1746,8 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
imapc->cmdid = (imapc->cmdid + 1) % 1000;
/* Calculate the tag based on the connection ID and command ID */
- snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
- 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
+ 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);
@@ -1793,7 +1790,7 @@ static char *imap_atom(const char *str, bool escape_only)
return NULL;
/* Look for "atom-specials", counting the backslash and quote characters as
- these will need escapping */
+ these will need escaping */
p1 = str;
while(*p1) {
if(*p1 == '\\')
diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c
index ac5d2d4d6..855981c66 100644
--- a/Utilities/cmcurl/lib/inet_ntop.c
+++ b/Utilities/cmcurl/lib/inet_ntop.c
@@ -55,11 +55,11 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
DEBUGASSERT(size >= 16);
tmp[0] = '\0';
- (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
- ((int)((unsigned char)src[0])) & 0xff,
- ((int)((unsigned char)src[1])) & 0xff,
- ((int)((unsigned char)src[2])) & 0xff,
- ((int)((unsigned char)src[3])) & 0xff);
+ (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+ ((int)((unsigned char)src[0])) & 0xff,
+ ((int)((unsigned char)src[1])) & 0xff,
+ ((int)((unsigned char)src[2])) & 0xff,
+ ((int)((unsigned char)src[3])) & 0xff);
len = strlen(tmp);
if(len == 0 || len >= size) {
@@ -148,7 +148,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
tp += strlen(tp);
break;
}
- tp += snprintf(tp, 5, "%lx", words[i]);
+ tp += msnprintf(tp, 5, "%lx", words[i]);
}
/* Was it a trailing run of 0x00's?
diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c
index fef9610d1..0d65ae0ec 100644
--- a/Utilities/cmcurl/lib/inet_pton.c
+++ b/Utilities/cmcurl/lib/inet_pton.c
@@ -153,7 +153,7 @@ inet_pton6(const char *src, unsigned char *dst)
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
- const char *xdigits, *curtok;
+ const char *curtok;
int ch, saw_xdigit;
size_t val;
@@ -168,6 +168,7 @@ inet_pton6(const char *src, unsigned char *dst)
saw_xdigit = 0;
val = 0;
while((ch = *src++) != '\0') {
+ const char *xdigits;
const char *pch;
pch = strchr((xdigits = xdigits_l), ch);
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index ceaa71d08..fd31faa3e 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -744,7 +744,7 @@ quit:
#endif
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
connclose(conn, "LDAP connection always disable re-use");
return result;
@@ -839,6 +839,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
{
int rc = LDAP_SUCCESS;
char *path;
+ char *query;
char *p;
char *q;
size_t i;
@@ -846,7 +847,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
if(!conn->data ||
!conn->data->state.up.path ||
conn->data->state.up.path[0] != '/' ||
- !strcasecompare("LDAP", conn->data->state.up.scheme))
+ !strncasecompare("LDAP", conn->data->state.up.scheme, 4))
return LDAP_INVALID_SYNTAX;
ludp->lud_scope = LDAP_SCOPE_BASE;
@@ -858,11 +859,14 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
if(!path)
return LDAP_NO_MEMORY;
- /* Parse the DN (Distinguished Name) */
- q = strchr(p, '?');
- if(q)
- *q++ = '\0';
+ /* Duplicate the query */
+ q = query = strdup(conn->data->state.up.query);
+ if(!query) {
+ free(path);
+ return LDAP_NO_MEMORY;
+ }
+ /* Parse the DN (Distinguished Name) */
if(*p) {
char *dn = p;
char *unescaped;
@@ -1039,6 +1043,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
quit:
free(path);
+ free(query);
return rc;
}
@@ -1064,8 +1069,6 @@ static int _ldap_url_parse(const struct connectdata *conn,
static void _ldap_free_urldesc(LDAPURLDesc *ludp)
{
- size_t i;
-
if(!ludp)
return;
@@ -1073,6 +1076,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp)
free(ludp->lud_filter);
if(ludp->lud_attrs) {
+ size_t i;
for(i = 0; i < ludp->lud_attrs_dups; i++)
free(ludp->lud_attrs[i]);
free(ludp->lud_attrs);
diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc
index 3316fba19..4839d0a65 100644
--- a/Utilities/cmcurl/lib/libcurl.rc
+++ b/Utilities/cmcurl/lib/libcurl.rc
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -22,22 +22,22 @@
#include <winver.h>
#include "../include/curl/curlver.h"
-LANGUAGE 0x09,0x01
+LANGUAGE 0, 0
#define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION RC_VERSION
PRODUCTVERSION RC_VERSION
- FILEFLAGSMASK 0x3fL
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#if defined(DEBUGBUILD) || defined(_DEBUG)
- FILEFLAGS 1
+ FILEFLAGS VS_FF_DEBUG
#else
- FILEFLAGS 0
+ FILEFLAGS 0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
- FILESUBTYPE 0x0L
+ FILESUBTYPE 0L
BEGIN
BLOCK "StringFileInfo"
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index d35060216..e7c77bc36 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -1,4 +1,5 @@
/*
+ * !checksrc! disable COPYRIGHT
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD4 Message-Digest Algorithm (RFC 1320).
*
@@ -37,9 +38,11 @@
#include "curl_setup.h"
-/* The NSS, OS/400 and sometimes mbed TLS crypto libraries do not provide the
- * MD4 hash algorithm, so we have a local implementation of it */
+/* The NSS, OS/400, and when not included, OpenSSL and mbed TLS crypto
+ * libraries do not provide the MD4 hash algorithm, so we use this
+ * implementation of it */
#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
+ (defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) || \
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
#include "curl_md4.h"
@@ -112,7 +115,6 @@ static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD4_u32plus a, b, c, d;
- MD4_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = (const unsigned char *)data;
@@ -122,6 +124,8 @@ static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
d = ctx->d;
do {
+ MD4_u32plus saved_a, saved_b, saved_c, saved_d;
+
saved_a = a;
saved_b = b;
saved_c = c;
@@ -129,59 +133,59 @@ static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 3)
- STEP(F, d, a, b, c, SET(1), 7)
- STEP(F, c, d, a, b, SET(2), 11)
- STEP(F, b, c, d, a, SET(3), 19)
- STEP(F, a, b, c, d, SET(4), 3)
- STEP(F, d, a, b, c, SET(5), 7)
- STEP(F, c, d, a, b, SET(6), 11)
- STEP(F, b, c, d, a, SET(7), 19)
- STEP(F, a, b, c, d, SET(8), 3)
- STEP(F, d, a, b, c, SET(9), 7)
- STEP(F, c, d, a, b, SET(10), 11)
- STEP(F, b, c, d, a, SET(11), 19)
- STEP(F, a, b, c, d, SET(12), 3)
- STEP(F, d, a, b, c, SET(13), 7)
- STEP(F, c, d, a, b, SET(14), 11)
- STEP(F, b, c, d, a, SET(15), 19)
+ STEP(F, d, a, b, c, SET(1), 7)
+ STEP(F, c, d, a, b, SET(2), 11)
+ STEP(F, b, c, d, a, SET(3), 19)
+ STEP(F, a, b, c, d, SET(4), 3)
+ STEP(F, d, a, b, c, SET(5), 7)
+ STEP(F, c, d, a, b, SET(6), 11)
+ STEP(F, b, c, d, a, SET(7), 19)
+ STEP(F, a, b, c, d, SET(8), 3)
+ STEP(F, d, a, b, c, SET(9), 7)
+ STEP(F, c, d, a, b, SET(10), 11)
+ STEP(F, b, c, d, a, SET(11), 19)
+ STEP(F, a, b, c, d, SET(12), 3)
+ STEP(F, d, a, b, c, SET(13), 7)
+ STEP(F, c, d, a, b, SET(14), 11)
+ STEP(F, b, c, d, a, SET(15), 19)
/* Round 2 */
- STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
- STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
- STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
- STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
- STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
- STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
- STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
- STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
- STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
- STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
- STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
- STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
- STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
- STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
- STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
- STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
/* Round 3 */
- STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
- STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
- STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
- STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
- STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
- STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
- STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
- STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
- STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
- STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
- STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
- STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
- STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
- STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
- STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
- STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
-
- a += saved_a;
+ STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
+
+ a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
@@ -211,7 +215,7 @@ static void MD4_Init(MD4_CTX *ctx)
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
MD4_u32plus saved_lo;
- unsigned long used, available;
+ unsigned long used;
saved_lo = ctx->lo;
ctx->lo = (saved_lo + size) & 0x1fffffff;
@@ -222,7 +226,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
used = saved_lo & 0x3f;
if(used) {
- available = 64 - used;
+ unsigned long available = 64 - used;
if(size < available) {
memcpy(&ctx->buffer[used], data, size);
@@ -303,5 +307,7 @@ void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len)
MD4_Update(&ctx, input, curlx_uztoui(len));
MD4_Final(output, &ctx);
}
+
#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) ||
+ (defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) ||
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 45f45bbd9..2b81ca455 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -39,19 +39,19 @@
typedef struct md5_ctx MD5_CTX;
-static void MD5_Init(MD5_CTX * ctx)
+static void MD5_Init(MD5_CTX *ctx)
{
md5_init(ctx);
}
-static void MD5_Update(MD5_CTX * ctx,
+static void MD5_Update(MD5_CTX *ctx,
const unsigned char *input,
unsigned int inputLen)
{
md5_update(ctx, inputLen, input);
}
-static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
{
md5_digest(ctx, 16, digest);
}
@@ -65,25 +65,25 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
typedef gcry_md_hd_t MD5_CTX;
-static void MD5_Init(MD5_CTX * ctx)
+static void MD5_Init(MD5_CTX *ctx)
{
gcry_md_open(ctx, GCRY_MD_MD5, 0);
}
-static void MD5_Update(MD5_CTX * ctx,
+static void MD5_Update(MD5_CTX *ctx,
const unsigned char *input,
unsigned int inputLen)
{
gcry_md_write(*ctx, input, inputLen);
}
-static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
{
memcpy(digest, gcry_md_read(*ctx, 0), 16);
gcry_md_close(*ctx);
}
-#elif defined(USE_OPENSSL)
+#elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
/* When OpenSSL is available we use the MD5-function from OpenSSL */
#include <openssl/md5.h>
#include "curl_memory.h"
@@ -124,7 +124,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
CC_MD5_Final(digest, ctx);
}
-#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP)
+#elif defined(WIN32) && !defined(CURL_WINDOWS_APP)
#include <wincrypt.h>
#include "curl_memory.h"
@@ -163,13 +163,6 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
CryptReleaseContext(ctx->hCryptProv, 0);
}
-#elif defined(USE_AXTLS)
-#include <axTLS/config.h>
-#include <axTLS/os_int.h>
-#include <axTLS/crypto.h>
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
#else
/* When no other crypto library is available we use this code segment */
/*
@@ -282,7 +275,6 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD5_u32plus a, b, c, d;
- MD5_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = (const unsigned char *)data;
@@ -292,6 +284,8 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
d = ctx->d;
do {
+ MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
saved_a = a;
saved_b = b;
saved_c = c;
@@ -299,77 +293,77 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
- STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
- STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
- STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
- STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
- STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
- STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
- STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
- STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
- STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
- STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
- STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
- STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
- STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
- STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
- STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
- STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
- STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
- STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
- STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
- STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
- STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
- STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
- STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
- STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
- STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
- STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
- STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
- STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
- STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
- STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
- STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
- STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
- STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
- STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
- STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
- STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
- STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
- STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
- STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
- STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
- STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
- STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
- STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
- STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
- STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
- STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
- STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
- STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
- STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
- STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
- STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
- STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
- STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
- STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
- STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
- STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
- STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
- STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
- STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
- STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
- STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
- STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
- STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
-
- a += saved_a;
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
@@ -399,7 +393,7 @@ static void MD5_Init(MD5_CTX *ctx)
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
MD5_u32plus saved_lo;
- unsigned long used, available;
+ unsigned long used;
saved_lo = ctx->lo;
ctx->lo = (saved_lo + size) & 0x1fffffff;
@@ -410,7 +404,7 @@ static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
used = saved_lo & 0x3f;
if(used) {
- available = 64 - used;
+ unsigned long available = 64 - used;
if(size < available) {
memcpy(&ctx->buffer[used], data, size);
@@ -552,23 +546,23 @@ MD5_context *Curl_MD5_init(const MD5_params *md5params)
return ctxt;
}
-int Curl_MD5_update(MD5_context *context,
- const unsigned char *data,
- unsigned int len)
+CURLcode Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len)
{
(*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
- return 0;
+ return CURLE_OK;
}
-int Curl_MD5_final(MD5_context *context, unsigned char *result)
+CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result)
{
(*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
free(context->md5_hashctx);
free(context);
- return 0;
+ return CURLE_OK;
}
#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
index 2b81c26a6..ede60094b 100644
--- a/Utilities/cmcurl/lib/memdebug.c
+++ b/Utilities/cmcurl/lib/memdebug.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -100,30 +100,29 @@ struct memdebug {
* Don't use these with multithreaded test programs!
*/
-#define logfile curl_debuglogfile
-FILE *curl_debuglogfile = NULL;
+FILE *curl_dbg_logfile = NULL;
static bool memlimit = FALSE; /* enable memory limit */
static long memsize = 0; /* set number of mallocs allowed */
/* this sets the log file name */
-void curl_memdebug(const char *logname)
+void curl_dbg_memdebug(const char *logname)
{
- if(!logfile) {
+ if(!curl_dbg_logfile) {
if(logname && *logname)
- logfile = fopen(logname, FOPEN_WRITETEXT);
+ curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
else
- logfile = stderr;
+ curl_dbg_logfile = stderr;
#ifdef MEMDEBUG_LOG_SYNC
/* Flush the log file after every line so the log isn't lost in a crash */
- if(logfile)
- setbuf(logfile, (char *)NULL);
+ if(curl_dbg_logfile)
+ setbuf(curl_dbg_logfile, (char *)NULL);
#endif
}
}
/* This function sets the number of malloc() calls that should return
successfully! */
-void curl_memlimit(long limit)
+void curl_dbg_memlimit(long limit)
{
if(!memlimit) {
memlimit = TRUE;
@@ -140,12 +139,12 @@ static bool countcheck(const char *func, int line, const char *source)
if(!memsize) {
if(source) {
/* log to file */
- curl_memlog("LIMIT %s:%d %s reached memlimit\n",
- source, line, func);
+ curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
/* log to stderr also */
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
source, line, func);
- fflush(logfile); /* because it might crash now */
+ fflush(curl_dbg_logfile); /* because it might crash now */
}
errno = ENOMEM;
return TRUE; /* RETURN ERROR! */
@@ -159,7 +158,7 @@ static bool countcheck(const char *func, int line, const char *source)
return FALSE; /* allow this */
}
-void *curl_domalloc(size_t wantedsize, int line, const char *source)
+void *curl_dbg_malloc(size_t wantedsize, int line, const char *source)
{
struct memdebug *mem;
size_t size;
@@ -180,15 +179,15 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
}
if(source)
- curl_memlog("MEM %s:%d malloc(%zu) = %p\n",
- source, line, wantedsize,
- mem ? (void *)mem->mem : (void *)0);
+ curl_dbg_log("MEM %s:%d malloc(%zu) = %p\n",
+ source, line, wantedsize,
+ mem ? (void *)mem->mem : (void *)0);
return (mem ? mem->mem : NULL);
}
-void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
- int line, const char *source)
+void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
+ int line, const char *source)
{
struct memdebug *mem;
size_t size, user_size;
@@ -208,14 +207,14 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
mem->size = user_size;
if(source)
- curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
- source, line, wanted_elements, wanted_size,
- mem ? (void *)mem->mem : (void *)0);
+ curl_dbg_log("MEM %s:%d calloc(%zu,%zu) = %p\n",
+ source, line, wanted_elements, wanted_size,
+ mem ? (void *)mem->mem : (void *)0);
return (mem ? mem->mem : NULL);
}
-char *curl_dostrdup(const char *str, int line, const char *source)
+char *curl_dbg_strdup(const char *str, int line, const char *source)
{
char *mem;
size_t len;
@@ -227,19 +226,19 @@ char *curl_dostrdup(const char *str, int line, const char *source)
len = strlen(str) + 1;
- mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+ mem = curl_dbg_malloc(len, 0, NULL); /* NULL prevents logging */
if(mem)
memcpy(mem, str, len);
if(source)
- curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
- source, line, (const void *)str, len, (const void *)mem);
+ curl_dbg_log("MEM %s:%d strdup(%p) (%zu) = %p\n",
+ source, line, (const void *)str, len, (const void *)mem);
return mem;
}
#if defined(WIN32) && defined(UNICODE)
-wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
+wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source)
{
wchar_t *mem;
size_t wsiz, bsiz;
@@ -252,12 +251,12 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
wsiz = wcslen(str) + 1;
bsiz = wsiz * sizeof(wchar_t);
- mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
+ mem = curl_dbg_malloc(bsiz, 0, NULL); /* NULL prevents logging */
if(mem)
memcpy(mem, str, bsiz);
if(source)
- curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
+ curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
source, line, (void *)str, bsiz, (void *)mem);
return mem;
@@ -266,8 +265,8 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
/* We provide a realloc() that accepts a NULL as pointer, which then
performs a malloc(). In order to work with ares. */
-void *curl_dorealloc(void *ptr, size_t wantedsize,
- int line, const char *source)
+void *curl_dbg_realloc(void *ptr, size_t wantedsize,
+ int line, const char *source)
{
struct memdebug *mem = NULL;
@@ -293,7 +292,7 @@ void *curl_dorealloc(void *ptr, size_t wantedsize,
mem = (Curl_crealloc)(mem, size);
if(source)
- curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
+ curl_dbg_log("MEM %s:%d realloc(%p, %zu) = %p\n",
source, line, (void *)ptr, wantedsize,
mem ? (void *)mem->mem : (void *)0);
@@ -305,11 +304,10 @@ void *curl_dorealloc(void *ptr, size_t wantedsize,
return NULL;
}
-void curl_dofree(void *ptr, int line, const char *source)
+void curl_dbg_free(void *ptr, int line, const char *source)
{
- struct memdebug *mem;
-
if(ptr) {
+ struct memdebug *mem;
#ifdef __INTEL_COMPILER
# pragma warning(push)
@@ -331,11 +329,11 @@ void curl_dofree(void *ptr, int line, const char *source)
}
if(source)
- curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
+ curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
}
-curl_socket_t curl_socket(int domain, int type, int protocol,
- int line, const char *source)
+curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
+ int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d socket() = %d\n" :
@@ -351,44 +349,44 @@ curl_socket_t curl_socket(int domain, int type, int protocol,
sockfd = socket(domain, type, protocol);
if(source && (sockfd != CURL_SOCKET_BAD))
- curl_memlog(fmt, source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
return sockfd;
}
-SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
- SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
- SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
- const char *source)
+SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd,
+ SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+ SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
+ const char *source)
{
SEND_TYPE_RETV rc;
if(countcheck("send", line, source))
return -1;
rc = send(sockfd, buf, len, flags);
if(source)
- curl_memlog("SEND %s:%d send(%lu) = %ld\n",
+ curl_dbg_log("SEND %s:%d send(%lu) = %ld\n",
source, line, (unsigned long)len, (long)rc);
return rc;
}
-RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
- RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
- const char *source)
+RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
+ RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
+ const char *source)
{
RECV_TYPE_RETV rc;
if(countcheck("recv", line, source))
return -1;
rc = recv(sockfd, buf, len, flags);
if(source)
- curl_memlog("RECV %s:%d recv(%lu) = %ld\n",
+ curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n",
source, line, (unsigned long)len, (long)rc);
return rc;
}
#ifdef HAVE_SOCKETPAIR
-int curl_socketpair(int domain, int type, int protocol,
- curl_socket_t socket_vector[2],
- int line, const char *source)
+int curl_dbg_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d socketpair() = %d %d\n" :
@@ -399,14 +397,14 @@ int curl_socketpair(int domain, int type, int protocol,
int res = socketpair(domain, type, protocol, socket_vector);
if(source && (0 == res))
- curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
+ curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]);
return res;
}
#endif
-curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
- int line, const char *source)
+curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
+ int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d accept() = %d\n" :
@@ -420,13 +418,13 @@ curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
curl_socket_t sockfd = accept(s, addr, addrlen);
if(source && (sockfd != CURL_SOCKET_BAD))
- curl_memlog(fmt, source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
return sockfd;
}
/* separate function to allow libcurl to mark a "faked" close */
-void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
+void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d sclose(%d)\n":
@@ -435,54 +433,40 @@ void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
"FD %s:%d sclose(%zd)\n";
if(source)
- curl_memlog(fmt, source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
}
/* this is our own defined way to close sockets on *ALL* platforms */
-int curl_sclose(curl_socket_t sockfd, int line, const char *source)
+int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source)
{
int res = sclose(sockfd);
- curl_mark_sclose(sockfd, line, source);
+ curl_dbg_mark_sclose(sockfd, line, source);
return res;
}
-FILE *curl_fopen(const char *file, const char *mode,
- int line, const char *source)
+FILE *curl_dbg_fopen(const char *file, const char *mode,
+ int line, const char *source)
{
FILE *res = fopen(file, mode);
if(source)
- curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+ curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
source, line, file, mode, (void *)res);
return res;
}
-#ifdef HAVE_FDOPEN
-FILE *curl_fdopen(int filedes, const char *mode,
- int line, const char *source)
-{
- FILE *res = fdopen(filedes, mode);
-
- if(source)
- curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
- source, line, filedes, mode, (void *)res);
-
- return res;
-}
-#endif
-
-int curl_fclose(FILE *file, int line, const char *source)
+int curl_dbg_fclose(FILE *file, int line, const char *source)
{
int res;
DEBUGASSERT(file != NULL);
- res = fclose(file);
-
if(source)
- curl_memlog("FILE %s:%d fclose(%p)\n",
- source, line, (void *)file);
+ curl_dbg_log("FILE %s:%d fclose(%p)\n",
+ source, line, (void *)file);
+
+ res = fclose(file);
return res;
}
@@ -490,13 +474,13 @@ int curl_fclose(FILE *file, int line, const char *source)
#define LOGLINE_BUFSIZE 1024
/* this does the writing to the memory tracking log file */
-void curl_memlog(const char *format, ...)
+void curl_dbg_log(const char *format, ...)
{
char *buf;
int nchars;
va_list ap;
- if(!logfile)
+ if(!curl_dbg_logfile)
return;
buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
@@ -504,14 +488,14 @@ void curl_memlog(const char *format, ...)
return;
va_start(ap, format);
- nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+ nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
va_end(ap);
if(nchars > LOGLINE_BUFSIZE - 1)
nchars = LOGLINE_BUFSIZE - 1;
if(nchars > 0)
- fwrite(buf, 1, (size_t)nchars, logfile);
+ fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile);
(Curl_cfree)(buf);
}
diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h
index 233de65a4..5236f60fa 100644
--- a/Utilities/cmcurl/lib/memdebug.h
+++ b/Utilities/cmcurl/lib/memdebug.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -30,97 +30,92 @@
#define CURL_MT_LOGFNAME_BUFSIZE 512
-#define logfile curl_debuglogfile
-
-extern FILE *logfile;
+extern FILE *curl_dbg_logfile;
/* memory functions */
-CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
-CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line,
- const char *source);
-CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line,
- const char *source);
-CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
-CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
-#if defined(WIN32) && defined(UNICODE)
-CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line,
+CURL_EXTERN void *curl_dbg_malloc(size_t size, int line, const char *source);
+CURL_EXTERN void *curl_dbg_calloc(size_t elements, size_t size, int line,
+ const char *source);
+CURL_EXTERN void *curl_dbg_realloc(void *ptr, size_t size, int line,
const char *source);
+CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source);
+CURL_EXTERN char *curl_dbg_strdup(const char *str, int line, const char *src);
+#if defined(WIN32) && defined(UNICODE)
+CURL_EXTERN wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line,
+ const char *source);
#endif
-CURL_EXTERN void curl_memdebug(const char *logname);
-CURL_EXTERN void curl_memlimit(long limit);
-CURL_EXTERN void curl_memlog(const char *format, ...);
+CURL_EXTERN void curl_dbg_memdebug(const char *logname);
+CURL_EXTERN void curl_dbg_memlimit(long limit);
+CURL_EXTERN void curl_dbg_log(const char *format, ...);
/* file descriptor manipulators */
-CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol,
- int line, const char *source);
-CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd,
- int line, const char *source);
-CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
- int line, const char *source);
-CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
+CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
+ int line, const char *source);
+CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd,
int line, const char *source);
-#ifdef HAVE_SOCKETPAIR
-CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
- curl_socket_t socket_vector[2],
+CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd,
int line, const char *source);
+CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen,
+ int line, const char *source);
+#ifdef HAVE_SOCKETPAIR
+CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line, const char *source);
#endif
/* send/receive sockets */
-CURL_EXTERN SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
- SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
- SEND_TYPE_ARG3 len,
- SEND_TYPE_ARG4 flags, int line,
- const char *source);
-CURL_EXTERN RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd,
- RECV_TYPE_ARG2 buf, RECV_TYPE_ARG3 len,
- RECV_TYPE_ARG4 flags, int line,
- const char *source);
+CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd,
+ SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+ SEND_TYPE_ARG3 len,
+ SEND_TYPE_ARG4 flags, int line,
+ const char *source);
+CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd,
+ RECV_TYPE_ARG2 buf,
+ RECV_TYPE_ARG3 len,
+ RECV_TYPE_ARG4 flags, int line,
+ const char *source);
/* FILE functions */
-CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
- const char *source);
-#ifdef HAVE_FDOPEN
-CURL_EXTERN FILE *curl_fdopen(int filedes, const char *mode, int line,
- const char *source);
-#endif
-CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
+CURL_EXTERN FILE *curl_dbg_fopen(const char *file, const char *mode, int line,
+ const char *source);
+CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
#ifndef MEMDEBUG_NODEFINES
/* Set this symbol on the command-line, recompile all lib-sources */
#undef strdup
-#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
-#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
-#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
-#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
-#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
-#define send(a,b,c,d) curl_dosend(a,b,c,d, __LINE__, __FILE__)
-#define recv(a,b,c,d) curl_dorecv(a,b,c,d, __LINE__, __FILE__)
+#define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
+#define malloc(size) curl_dbg_malloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__)
+#define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__)
+#define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__)
+#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__)
+#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__)
#ifdef WIN32
# ifdef UNICODE
# undef wcsdup
-# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
# undef _wcsdup
-# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
# undef _tcsdup
-# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
# else
# undef _tcsdup
-# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+# define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
# endif
#endif
#undef socket
#define socket(domain,type,protocol)\
- curl_socket(domain, type, protocol, __LINE__, __FILE__)
+ curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__)
#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
- curl_accept(sock, addr, len, __LINE__, __FILE__)
+ curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
#ifdef HAVE_SOCKETPAIR
#define socketpair(domain,type,protocol,socket_vector)\
- curl_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)
+ curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)
#endif
#ifdef HAVE_GETADDRINFO
@@ -129,31 +124,31 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
our macro as for other platforms. Instead, we redefine the new name they
define getaddrinfo to become! */
#define ogetaddrinfo(host,serv,hint,res) \
- curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
#else
#undef getaddrinfo
#define getaddrinfo(host,serv,hint,res) \
- curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
#endif
#endif /* HAVE_GETADDRINFO */
#ifdef HAVE_FREEADDRINFO
#undef freeaddrinfo
#define freeaddrinfo(data) \
- curl_dofreeaddrinfo(data, __LINE__, __FILE__)
+ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
#endif /* HAVE_FREEADDRINFO */
/* sclose is probably already defined, redefine it! */
#undef sclose
-#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__)
-#define fake_sclose(sockfd) curl_mark_sclose(sockfd,__LINE__,__FILE__)
+#define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__)
#undef fopen
-#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
+#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
#undef fdopen
-#define fdopen(file,mode) curl_fdopen(file,mode,__LINE__,__FILE__)
-#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
+#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
#endif /* MEMDEBUG_NODEFINES */
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index ca492d11a..2135f72c2 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -29,8 +29,8 @@
#include "urldata.h"
#include "sendf.h"
-#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
- !defined(CURL_DISABLE_IMAP)
+#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
+ !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
#include <libgen.h>
@@ -821,8 +821,10 @@ static size_t readback_part(curl_mimepart *part,
struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
switch(part->state.state) {
case MIMESTATE_BEGIN:
- mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY:
- MIMESTATE_CURLHEADERS, part->curlheaders);
+ mimesetstate(&part->state,
+ (part->flags & MIME_BODY_ONLY)?
+ MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
+ part->curlheaders);
break;
case MIMESTATE_USERHEADERS:
if(!hdr) {
@@ -1122,8 +1124,6 @@ void curl_mime_free(curl_mime *mime)
Curl_mime_cleanpart(part);
free(part);
}
-
- free(mime->boundary);
free(mime);
}
}
@@ -1220,18 +1220,10 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
mime->firstpart = NULL;
mime->lastpart = NULL;
- /* Get a part boundary. */
- mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1);
- if(!mime->boundary) {
- free(mime);
- return NULL;
- }
-
memset(mime->boundary, '-', 24);
- if(Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24,
+ if(Curl_rand_hex(easy, (unsigned char *) &mime->boundary[24],
MIME_RAND_BOUNDARY_CHARS + 1)) {
/* failed to get random separator, bail out */
- free(mime->boundary);
free(mime);
return NULL;
}
@@ -1909,72 +1901,4 @@ CURLcode curl_mime_headers(curl_mimepart *part,
return CURLE_NOT_BUILT_IN;
}
-void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
-{
- (void) part;
- (void) easy;
-}
-
-void Curl_mime_cleanpart(curl_mimepart *part)
-{
- (void) part;
-}
-
-CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
-{
- (void) dst;
- (void) src;
- return CURLE_OK; /* Nothing to duplicate: always succeed. */
-}
-
-CURLcode Curl_mime_set_subparts(curl_mimepart *part,
- curl_mime *subparts, int take_ownership)
-{
- (void) part;
- (void) subparts;
- (void) take_ownership;
- return CURLE_NOT_BUILT_IN;
-}
-
-CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
- const char *contenttype,
- const char *disposition,
- enum mimestrategy strategy)
-{
- (void) part;
- (void) contenttype;
- (void) disposition;
- (void) strategy;
- return CURLE_NOT_BUILT_IN;
-}
-
-curl_off_t Curl_mime_size(curl_mimepart *part)
-{
- (void) part;
- return (curl_off_t) -1;
-}
-
-size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
-{
- (void) buffer;
- (void) size;
- (void) nitems;
- (void) instream;
- return 0;
-}
-
-CURLcode Curl_mime_rewind(curl_mimepart *part)
-{
- (void) part;
- return CURLE_NOT_BUILT_IN;
-}
-
-/* VARARGS2 */
-CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
-{
- (void) slp;
- (void) fmt;
- return CURLE_NOT_BUILT_IN;
-}
-
-#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
+#endif /* if disabled */
diff --git a/Utilities/cmcurl/lib/mime.h b/Utilities/cmcurl/lib/mime.h
index 4d5c70404..4c9a5fb71 100644
--- a/Utilities/cmcurl/lib/mime.h
+++ b/Utilities/cmcurl/lib/mime.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,6 +22,8 @@
*
***************************************************************************/
+#include "curl_setup.h"
+
#define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */
#define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */
#define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */
@@ -69,7 +71,7 @@ enum mimestrategy {
typedef struct {
const char * name; /* Encoding name. */
size_t (*encodefunc)(char *buffer, size_t size, bool ateof,
- curl_mimepart *part); /* Encoded read. */
+ curl_mimepart *part); /* Encoded read. */
curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */
} mime_encoder;
@@ -88,13 +90,16 @@ typedef struct {
size_t offset; /* State-dependent offset. */
} mime_state;
+/* minimum buffer size for the boundary string */
+#define MIME_BOUNDARY_LEN (24 + MIME_RAND_BOUNDARY_CHARS + 1)
+
/* A mime multipart. */
struct curl_mime_s {
struct Curl_easy *easy; /* The associated easy handle. */
curl_mimepart *parent; /* Parent part. */
curl_mimepart *firstpart; /* First part. */
curl_mimepart *lastpart; /* Last part. */
- char *boundary; /* The part boundary. */
+ char boundary[MIME_BOUNDARY_LEN]; /* The part boundary. */
mime_state state; /* Current readback state. */
};
@@ -122,6 +127,8 @@ struct curl_mimepart_s {
mime_encoder_state encstate; /* Data encoder state. */
};
+#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
+ !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
/* Prototypes. */
void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy);
@@ -140,4 +147,18 @@ CURLcode Curl_mime_rewind(curl_mimepart *part);
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
const char *Curl_mime_contenttype(const char *filename);
+#else
+/* if disabled */
+#define Curl_mime_initpart(x,y)
+#define Curl_mime_cleanpart(x)
+#define Curl_mime_duppart(x,y) CURLE_OK /* Nothing to duplicate. Succeed */
+#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_mime_prepare_headers(a,b,c,d) CURLE_NOT_BUILT_IN
+#define Curl_mime_size(x) (curl_off_t) -1
+#define Curl_mime_read NULL
+#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define Curl_mime_add_header(x,y,...) CURLE_NOT_BUILT_IN
+#endif
+
+
#endif /* HEADER_CURL_MIME_H */
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index d2d91d743..e19093678 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -835,7 +835,7 @@ static int dprintf_formatf(
while(width-- > 0)
OUTCHAR(' ');
- while((len-- > 0) && *str)
+ for(; len && *str; len--)
OUTCHAR(*str++);
if(p->flags&FLAGS_LEFT)
while(width-- > 0)
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 0db2a9730..c7c46eefc 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -41,11 +41,11 @@
#include "speedcheck.h"
#include "conncache.h"
#include "multihandle.h"
-#include "pipeline.h"
#include "sigpipe.h"
#include "vtls/vtls.h"
#include "connect.h"
#include "http_proxy.h"
+#include "http2.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -79,6 +79,7 @@ static CURLMcode add_next_timeout(struct curltime now,
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
+static void detach_connnection(struct Curl_easy *data);
#ifdef DEBUGBUILD
static const char * const statename[]={
@@ -90,12 +91,10 @@ static const char * const statename[]={
"WAITPROXYCONNECT",
"SENDPROTOCONNECT",
"PROTOCONNECT",
- "WAITDO",
"DO",
"DOING",
"DO_MORE",
"DO_DONE",
- "WAITPERFORM",
"PERFORM",
"TOOFAST",
"DONE",
@@ -113,7 +112,7 @@ static void Curl_init_completed(struct Curl_easy *data)
/* Important: reset the conn pointer so that we don't point to memory
that could be freed anytime */
- data->easy_conn = NULL;
+ detach_connnection(data);
Curl_expire_clear(data); /* stop all timers */
}
@@ -134,12 +133,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL, /* WAITPROXYCONNECT */
NULL, /* SENDPROTOCONNECT */
NULL, /* PROTOCONNECT */
- NULL, /* WAITDO */
Curl_connect_free, /* DO */
NULL, /* DOING */
NULL, /* DO_MORE */
NULL, /* DO_DONE */
- NULL, /* WAITPERFORM */
NULL, /* PERFORM */
NULL, /* TOOFAST */
NULL, /* DONE */
@@ -162,8 +159,8 @@ static void mstate(struct Curl_easy *data, CURLMstate state
data->mstate < CURLM_STATE_COMPLETED) {
long connection_id = -5000;
- if(data->easy_conn)
- connection_id = data->easy_conn->connection_id;
+ if(data->conn)
+ connection_id = data->conn->connection_id;
infof(data,
"STATE: %s => %s handle %p; line %d (connection #%ld)\n",
@@ -188,14 +185,17 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#endif
/*
- * We add one of these structs to the sockhash for a particular socket
+ * We add one of these structs to the sockhash for each socket
*/
struct Curl_sh_entry {
- struct Curl_easy *easy;
- int action; /* what action READ/WRITE this socket waits for */
- curl_socket_t socket; /* mainly to ease debugging */
+ struct curl_llist list; /* list of easy handles 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 */
+ unsigned int readers; /* this many transfers want to read */
+ unsigned int writers; /* this many transfers want to write */
};
/* bits for 'action' having no bits means this socket is not expecting any
action */
@@ -214,8 +214,7 @@ static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
/* make sure this socket is present in the hash for this handle */
static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
- curl_socket_t s,
- struct Curl_easy *data)
+ curl_socket_t s)
{
struct Curl_sh_entry *there = sh_getentry(sh, s);
struct Curl_sh_entry *check;
@@ -229,8 +228,7 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
if(!check)
return NULL; /* major failure */
- check->easy = data;
- check->socket = s;
+ Curl_llist_init(&check->list, NULL);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
@@ -346,9 +344,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->msglist, multi_freeamsg);
Curl_llist_init(&multi->pending, multi_freeamsg);
- multi->max_pipeline_length = 5;
- multi->pipelining = CURLPIPE_MULTIPLEX;
-
/* -1 means it not set by user, use the default value */
multi->maxconnects = -1;
return multi;
@@ -405,19 +400,9 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
/* set the easy handle */
multistate(data, CURLM_STATE_INIT);
- if((data->set.global_dns_cache) &&
- (data->dns.hostcachetype != HCACHE_GLOBAL)) {
- /* global dns cache was requested but still isn't */
- struct curl_hash *global = Curl_global_host_cache_init();
- if(global) {
- /* only do this if the global cache init works */
- data->dns.hostcache = global;
- data->dns.hostcachetype = HCACHE_GLOBAL;
- }
- }
/* for multi interface connections, we share DNS cache automatically if the
easy handle's one is currently not set. */
- else if(!data->dns.hostcache ||
+ if(!data->dns.hostcache ||
(data->dns.hostcachetype == HCACHE_NONE)) {
data->dns.hostcache = &multi->hostcache;
data->dns.hostcachetype = HCACHE_MULTI;
@@ -437,12 +422,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->psl = &multi->psl;
#endif
- /* This adds the new entry at the 'end' of the doubly-linked circular
- list of Curl_easy structs to try and maintain a FIFO queue so
- the pipelined requests are in order. */
-
- /* We add this new entry last in the list. */
-
+ /* We add the new entry last in the list. */
data->next = NULL; /* end of the line */
if(multi->easyp) {
struct Curl_easy *last = multi->easylp;
@@ -515,33 +495,23 @@ static void debug_print_sock_hash(void *p)
}
#endif
-static CURLcode multi_done(struct connectdata **connp,
- CURLcode status, /* an error if this is called
- after an error was detected */
- bool premature)
+static CURLcode multi_done(struct Curl_easy *data,
+ CURLcode status, /* an error if this is called
+ after an error was detected */
+ bool premature)
{
CURLcode result;
- struct connectdata *conn;
- struct Curl_easy *data;
+ struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGASSERT(*connp);
-
- conn = *connp;
- data = conn->data;
-
DEBUGF(infof(data, "multi_done\n"));
if(data->state.done)
/* Stop if multi_done() has already been called */
return CURLE_OK;
- if(data->mstate == CURLM_STATE_WAITRESOLVE) {
- /* still waiting for the resolve to complete */
- (void)Curl_resolver_wait_resolv(conn, NULL);
- }
-
- Curl_getoff_all_pipelines(data, conn);
+ /* Stop the resolver and free its own resources (but not dns_entry yet). */
+ Curl_resolver_kill(conn);
/* Cleanup possible redirect junk */
Curl_safefree(data->req.newurl);
@@ -576,17 +546,16 @@ static CURLcode multi_done(struct connectdata **connp,
process_pending_handles(data->multi); /* connection / multiplex */
- if(conn->send_pipe.size || conn->recv_pipe.size) {
- /* Stop if pipeline is not empty . */
- data->easy_conn = NULL;
- DEBUGF(infof(data, "Connection still in use %zu/%zu, "
+ detach_connnection(data);
+ if(CONN_INUSE(conn)) {
+ /* Stop if still used. */
+ DEBUGF(infof(data, "Connection still in use %zu, "
"no more multi_done now!\n",
- conn->send_pipe.size, conn->recv_pipe.size));
+ conn->easyq.size));
return CURLE_OK;
}
data->state.done = TRUE; /* called just now! */
- Curl_resolver_cancel(conn);
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
@@ -604,7 +573,7 @@ static CURLcode multi_done(struct connectdata **connp,
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this connection. This is ignored for requests taking
- place in a NTLM authentication handshake
+ place in a NTLM/NEGOTIATE authentication handshake
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
@@ -619,8 +588,12 @@ static CURLcode multi_done(struct connectdata **connp,
if((data->set.reuse_forbid
#if defined(USE_NTLM)
- && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
- conn->proxyntlm.state == NTLMSTATE_TYPE2)
+ && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
+ conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
+#endif
+#if defined(USE_SPNEGO)
+ && !(conn->http_negotiate_state == GSS_AUTHRECV ||
+ conn->proxy_negotiate_state == GSS_AUTHRECV)
#endif
) || conn->bits.close
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
@@ -634,13 +607,13 @@ static CURLcode multi_done(struct connectdata **connp,
else {
char buffer[256];
/* create string before returning the connection */
- snprintf(buffer, sizeof(buffer),
- "Connection #%ld to host %s left intact",
- conn->connection_id,
- conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
- conn->bits.httpproxy ? conn->http_proxy.host.dispname :
- conn->bits.conn_to_host ? conn->conn_to_host.dispname :
- conn->host.dispname);
+ msnprintf(buffer, sizeof(buffer),
+ "Connection #%ld to host %s left intact",
+ conn->connection_id,
+ conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
+ conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+ conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+ conn->host.dispname);
/* the connection is no longer in use by this transfer */
if(Curl_conncache_return_conn(conn)) {
@@ -652,10 +625,6 @@ static CURLcode multi_done(struct connectdata **connp,
data->state.lastconnect = NULL;
}
- *connp = NULL; /* to make the caller of this function better detect that
- this was either closed or handed over to the connection
- cache here, and therefore cannot be used from this point on
- */
Curl_free_request_state(data);
return result;
}
@@ -684,7 +653,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
return CURLM_RECURSIVE_API_CALL;
premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
- easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
+ easy_owns_conn = (data->conn && (data->conn->data == easy)) ?
TRUE : FALSE;
/* If the 'state' is not INIT or COMPLETED, we might need to do something
@@ -695,16 +664,13 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
multi->num_alive--;
}
- if(data->easy_conn &&
+ if(data->conn &&
data->mstate > CURLM_STATE_DO &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
- data->easy_conn->data = easy;
- /* If the handle is in a pipeline and has started sending off its
- request but not received its response yet, we need to close
- connection. */
- streamclose(data->easy_conn, "Removed with partial response");
+ data->conn->data = easy;
+ streamclose(data->conn, "Removed with partial response");
easy_owns_conn = TRUE;
}
@@ -713,7 +679,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
curl_easy_cleanup is called. */
Curl_expire_clear(data);
- if(data->easy_conn) {
+ if(data->conn) {
/* we must call multi_done() here (if we still own the connection) so that
we don't leave a half-baked one around */
@@ -724,11 +690,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
Note that this ignores the return code simply because there's
nothing really useful to do with it anyway! */
- (void)multi_done(&data->easy_conn, data->result, premature);
+ (void)multi_done(data, data->result, premature);
}
- else
- /* Clear connection pipelines, if multi_done above was not called */
- Curl_getoff_all_pipelines(data, data->easy_conn);
}
if(data->connect_queue.ptr)
@@ -760,9 +723,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
vanish with this handle */
/* Remove the association between the connection and the handle */
- if(data->easy_conn) {
- data->easy_conn->data = NULL;
- data->easy_conn = NULL;
+ if(data->conn) {
+ data->conn->data = NULL;
+ detach_connnection(data);
}
#ifdef USE_LIBPSL
@@ -806,15 +769,31 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
return CURLM_OK;
}
-/* Return TRUE if the application asked for a certain set of pipelining */
-bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
+/* Return TRUE if the application asked for multiplexing */
+bool Curl_multiplex_wanted(const struct Curl_multi *multi)
+{
+ return (multi && (multi->multiplexing));
+}
+
+/* This is the only function that should clear data->conn. This will
+ occasionally be called with the pointer already cleared. */
+static void detach_connnection(struct Curl_easy *data)
{
- return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
+ struct connectdata *conn = data->conn;
+ if(conn)
+ Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
+ data->conn = NULL;
}
-void Curl_multi_handlePipeBreak(struct Curl_easy *data)
+/* This is the only function that should assign data->conn */
+void Curl_attach_connnection(struct Curl_easy *data,
+ struct connectdata *conn)
{
- data->easy_conn = NULL;
+ DEBUGASSERT(!data->conn);
+ DEBUGASSERT(conn);
+ data->conn = conn;
+ Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
+ &data->conn_queue);
}
static int waitconnect_getsock(struct connectdata *conn,
@@ -878,13 +857,13 @@ static int multi_getsock(struct Curl_easy *data,
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
- if(!data->easy_conn)
+ if(!data->conn)
return 0;
if(data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Set up ownership correctly */
- data->easy_conn->data = data;
+ data->conn->data = data;
}
switch(data->mstate) {
@@ -905,31 +884,30 @@ static int multi_getsock(struct Curl_easy *data,
return 0;
case CURLM_STATE_WAITRESOLVE:
- return Curl_resolv_getsock(data->easy_conn, socks, numsocks);
+ return Curl_resolv_getsock(data->conn, socks, numsocks);
case CURLM_STATE_PROTOCONNECT:
case CURLM_STATE_SENDPROTOCONNECT:
- return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
+ return Curl_protocol_getsock(data->conn, socks, numsocks);
case CURLM_STATE_DO:
case CURLM_STATE_DOING:
- return Curl_doing_getsock(data->easy_conn, socks, numsocks);
+ return Curl_doing_getsock(data->conn, socks, numsocks);
case CURLM_STATE_WAITPROXYCONNECT:
- return waitproxyconnect_getsock(data->easy_conn, socks, numsocks);
+ return waitproxyconnect_getsock(data->conn, socks, numsocks);
case CURLM_STATE_WAITCONNECT:
- return waitconnect_getsock(data->easy_conn, socks, numsocks);
+ return waitconnect_getsock(data->conn, socks, numsocks);
case CURLM_STATE_DO_MORE:
- return domore_getsock(data->easy_conn, socks, numsocks);
+ return domore_getsock(data->conn, socks, numsocks);
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:
- case CURLM_STATE_WAITPERFORM:
- return Curl_single_getsock(data->easy_conn, socks, numsocks);
+ return Curl_single_getsock(data->conn, socks, numsocks);
}
}
@@ -985,11 +963,12 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
#define NUM_POLLS_ON_STACK 10
-CURLMcode curl_multi_wait(struct Curl_multi *multi,
+CURLMcode Curl_multi_wait(struct Curl_multi *multi,
struct curl_waitfd extra_fds[],
unsigned int extra_nfds,
int timeout_ms,
- int *ret)
+ int *ret,
+ bool *gotsocket) /* if any socket was checked */
{
struct Curl_easy *data;
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
@@ -997,11 +976,14 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
unsigned int i;
unsigned int nfds = 0;
unsigned int curlfds;
- struct pollfd *ufds = NULL;
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];
+
+ if(gotsocket)
+ *gotsocket = FALSE;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1043,19 +1025,15 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
curlfds = nfds; /* number of internal file descriptors */
nfds += extra_nfds; /* add the externally provided ones */
- if(nfds) {
- if(nfds > NUM_POLLS_ON_STACK) {
- /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
- big, so at 2^29 sockets this value might wrap. When a process gets
- the capability to actually handle over 500 million sockets this
- calculation needs a integer overflow check. */
- ufds = malloc(nfds * sizeof(struct pollfd));
- if(!ufds)
- return CURLM_OUT_OF_MEMORY;
- ufds_malloc = TRUE;
- }
- else
- ufds = &a_few_on_stack[0];
+ if(nfds > NUM_POLLS_ON_STACK) {
+ /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
+ big, so at 2^29 sockets this value might wrap. When a process gets
+ the capability to actually handle over 500 million sockets this
+ calculation needs a integer overflow check. */
+ ufds = malloc(nfds * sizeof(struct pollfd));
+ if(!ufds)
+ return CURLM_OUT_OF_MEMORY;
+ ufds_malloc = TRUE;
}
nfds = 0;
@@ -1135,19 +1113,20 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
free(ufds);
if(ret)
*ret = retcode;
+ if(gotsocket && (extra_fds || curlfds))
+ /* if any socket was checked */
+ *gotsocket = TRUE;
+
return CURLM_OK;
}
-/*
- * Curl_multi_connchanged() is called to tell that there is a connection in
- * this multi handle that has changed state (pipelining become possible, the
- * number of allowed streams changed or similar), and a subsequent use of this
- * multi handle should move CONNECT_PEND handles back to CONNECT to have them
- * retry.
- */
-void Curl_multi_connchanged(struct Curl_multi *multi)
+CURLMcode curl_multi_wait(struct Curl_multi *multi,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret)
{
- multi->recheckstate = TRUE;
+ return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, NULL);
}
/*
@@ -1185,111 +1164,36 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* take this handle to the perform state right away */
multistate(data, CURLM_STATE_PERFORM);
- data->easy_conn = conn;
+ Curl_attach_connnection(data, conn);
k->keepon |= KEEP_RECV; /* setup to receive! */
}
return rc;
}
-static CURLcode multi_reconnect_request(struct connectdata **connp)
-{
- CURLcode result = CURLE_OK;
- struct connectdata *conn = *connp;
- struct Curl_easy *data = conn->data;
-
- /* This was a re-use of a connection and we got a write error in the
- * DO-phase. Then we DISCONNECT this connection and have another attempt to
- * CONNECT and then DO again! The retry cannot possibly find another
- * connection to re-use, since we only keep one possible connection for
- * each. */
-
- infof(data, "Re-used connection seems dead, get a new one\n");
-
- connclose(conn, "Reconnect dead connection"); /* enforce close */
- result = multi_done(&conn, result, FALSE); /* we are so done with this */
-
- /* conn may no longer be a good pointer, clear it to avoid mistakes by
- parent functions */
- *connp = NULL;
-
- /*
- * We need to check for CURLE_SEND_ERROR here as well. This could happen
- * when the request failed on a FTP connection and thus multi_done() itself
- * tried to use the connection (again).
- */
- if(!result || (CURLE_SEND_ERROR == result)) {
- bool async;
- bool protocol_done = TRUE;
-
- /* Now, redo the connect and get a new connection */
- result = Curl_connect(data, connp, &async, &protocol_done);
- if(!result) {
- /* We have connected or sent away a name resolve query fine */
-
- conn = *connp; /* setup conn to again point to something nice */
- if(async) {
- /* Now, if async is TRUE here, we need to wait for the name
- to resolve */
- result = Curl_resolver_wait_resolv(conn, NULL);
- if(result)
- return result;
-
- /* Resolved, continue with the connection */
- result = Curl_once_resolved(conn, &protocol_done);
- if(result)
- return result;
- }
- }
- }
-
- return result;
-}
-
/*
* 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 in the pipeline.
+ * before receiving any header data for the current request.
*/
static void do_complete(struct connectdata *conn)
{
conn->data->req.chunk = FALSE;
- conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
- conn->sockfd:conn->writesockfd) + 1;
Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
}
-static CURLcode multi_do(struct connectdata **connp, bool *done)
+static CURLcode multi_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = *connp;
- struct Curl_easy *data = conn->data;
+ struct connectdata *conn = data->conn;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->handler);
if(conn->handler->do_it) {
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->handler->do_it(conn, done);
- /* This was formerly done in transfer.c, but we better do it here */
- if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
- /*
- * If the connection is using an easy handle, call reconnect
- * to re-establish the connection. Otherwise, let the multi logic
- * figure out how to re-establish the connection.
- */
- if(!data->multi) {
- result = multi_reconnect_request(connp);
-
- if(!result) {
- /* ... finally back to actually retry the DO phase */
- conn = *connp; /* re-assign conn since multi_reconnect_request
- creates a new connection */
- result = conn->handler->do_it(conn, done);
- }
- }
- else
- return result;
- }
-
if(!result && *done)
/* do_complete must be called after the protocol-specific DO function */
do_complete(conn);
@@ -1302,8 +1206,6 @@ static CURLcode multi_do(struct connectdata **connp, bool *done)
* second stage DO state which (wrongly) was introduced to support FTP's
* second connection.
*
- * TODO: A future libcurl should be able to work away this state.
- *
* 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
* DOING state there's more work to do!
*/
@@ -1336,9 +1238,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
- struct SingleRequest *k;
- time_t timeout_ms;
- time_t recv_timeout_ms;
+ timediff_t timeout_ms;
+ timediff_t recv_timeout_ms;
timediff_t send_timeout_ms;
int control;
@@ -1351,56 +1252,59 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool stream_error = FALSE;
rc = CURLM_OK;
- if(!data->easy_conn &&
+ if(!data->conn &&
data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_DONE) {
- /* In all these states, the code will blindly access 'data->easy_conn'
+ /* In all these states, the code will blindly access 'data->conn'
so this is precaution that it isn't NULL. And it silences static
analyzers. */
- failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
+ failf(data, "In state %d with no conn, bail out!\n", data->mstate);
return CURLM_INTERNAL_ERROR;
}
if(multi_ischanged(multi, TRUE)) {
DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
- process_pending_handles(multi); /* pipelined/multiplexed */
+ process_pending_handles(multi); /* multiplexed */
}
- if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
+ if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Make sure we set the connection's current owner */
- data->easy_conn->data = data;
+ data->conn->data = data;
}
- if(data->easy_conn &&
+ if(data->conn &&
(data->mstate >= CURLM_STATE_CONNECT) &&
(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,
- (data->mstate <= CURLM_STATE_WAITDO)?
+ (data->mstate <= CURLM_STATE_DO)?
TRUE:FALSE);
if(timeout_ms < 0) {
/* Handle timed out */
if(data->mstate == CURLM_STATE_WAITRESOLVE)
- failf(data, "Resolving timed out after %ld milliseconds",
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
Curl_timediff(now, data->progress.t_startsingle));
else if(data->mstate == CURLM_STATE_WAITCONNECT)
- failf(data, "Connection timed out after %ld milliseconds",
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
Curl_timediff(now, data->progress.t_startsingle));
else {
- k = &data->req;
+ struct SingleRequest *k = &data->req;
if(k->size != -1) {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " out of %"
+ 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),
k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
+ 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),
k->bytecount);
}
@@ -1408,11 +1312,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Force connection closed if the connection has indeed been used */
if(data->mstate > CURLM_STATE_DO) {
- streamclose(data->easy_conn, "Disconnected with pending data");
+ streamclose(data->conn, "Disconnected with pending data");
stream_error = TRUE;
}
result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(&data->easy_conn, result, TRUE);
+ (void)multi_done(data, result, TRUE);
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
@@ -1439,8 +1343,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
Curl_pgrsTime(data, TIMER_STARTSINGLE);
- result = Curl_connect(data, &data->easy_conn,
- &async, &protocol_connect);
+ if(data->set.timeout)
+ Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
+
+ if(data->set.connecttimeout)
+ Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
+
+ result = Curl_connect(data, &async, &protocol_connect);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
@@ -1452,33 +1361,31 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = CURLE_OK;
break;
}
+ else if(data->state.previouslypending) {
+ /* this transfer comes from the pending queue so try move another */
+ infof(data, "Transfer was pending, now try another\n");
+ process_pending_handles(data->multi);
+ }
if(!result) {
- /* Add this handle to the send or pend pipeline */
- result = Curl_add_handle_to_pipeline(data, data->easy_conn);
- if(result)
- stream_error = TRUE;
+ if(async)
+ /* We're now waiting for an asynchronous name lookup */
+ multistate(data, CURLM_STATE_WAITRESOLVE);
else {
- if(async)
- /* We're now waiting for an asynchronous name lookup */
- multistate(data, CURLM_STATE_WAITRESOLVE);
- else {
- /* after the connect has been sent off, go WAITCONNECT unless the
- protocol connect is already done and we can go directly to
- WAITDO or DO! */
- rc = CURLM_CALL_MULTI_PERFORM;
+ /* after the connect has been sent off, go WAITCONNECT unless the
+ protocol connect is already done and we can go directly to
+ WAITDO or DO! */
+ rc = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connect)
- multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
- CURLM_STATE_WAITDO:CURLM_STATE_DO);
- else {
+ if(protocol_connect)
+ multistate(data, CURLM_STATE_DO);
+ else {
#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->easy_conn))
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
- else
+ if(Curl_connect_ongoing(data->conn))
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
#endif
- multistate(data, CURLM_STATE_WAITCONNECT);
- }
+ multistate(data, CURLM_STATE_WAITCONNECT);
}
}
}
@@ -1488,9 +1395,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* awaiting an asynch name resolve to complete */
{
struct Curl_dns_entry *dns = NULL;
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
const char *hostname;
+ DEBUGASSERT(conn);
if(conn->bits.httpproxy)
hostname = conn->http_proxy.host.name;
else if(conn->bits.conn_to_host)
@@ -1511,7 +1419,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!dns)
- result = Curl_resolv_check(data->easy_conn, &dns);
+ result = Curl_resolv_check(data->conn, &dns);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
@@ -1524,21 +1432,20 @@ 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->easy_conn, &protocol_connect);
+ result = Curl_once_resolved(data->conn, &protocol_connect);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct
is already freed and gone */
- data->easy_conn = NULL; /* no more connection */
+ data->conn = NULL; /* no more connection */
else {
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connect)
- multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
- CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ multistate(data, CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->easy_conn))
+ if(Curl_connect_ongoing(data->conn))
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
else
#endif
@@ -1558,19 +1465,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_HTTP
case CURLM_STATE_WAITPROXYCONNECT:
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
- result = Curl_http_connect(data->easy_conn, &protocol_connect);
+ DEBUGASSERT(data->conn);
+ result = Curl_http_connect(data->conn, &protocol_connect);
- if(data->easy_conn->bits.proxy_connect_closed) {
+ if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
/* connect back to proxy again */
result = CURLE_OK;
- multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multi_done(data, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_CONNECT);
}
else if(!result) {
- if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
- data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
- Curl_connect_complete(data->easy_conn)) {
+ if((data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
+ data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
+ Curl_connect_complete(data->conn)) {
rc = CURLM_CALL_MULTI_PERFORM;
/* initiate protocol connect phase */
multistate(data, CURLM_STATE_SENDPROTOCONNECT);
@@ -1583,101 +1491,94 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_WAITCONNECT:
/* awaiting a completion of an asynch TCP connect */
- result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected);
+ DEBUGASSERT(data->conn);
+ result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
- if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
- !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
- Curl_connect_ongoing(data->easy_conn)) {
+ if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
+ !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
+ Curl_connect_ongoing(data->conn)) {
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
break;
}
#endif
rc = CURLM_CALL_MULTI_PERFORM;
- multistate(data, data->easy_conn->bits.tunnel_proxy?
+ multistate(data, data->conn->bits.tunnel_proxy?
CURLM_STATE_WAITPROXYCONNECT:
CURLM_STATE_SENDPROTOCONNECT);
}
else if(result) {
/* failure detected */
- /* Just break, the cleaning up is handled all in one place */
+ Curl_posttransfer(data);
+ multi_done(data, result, TRUE);
stream_error = TRUE;
break;
}
break;
case CURLM_STATE_SENDPROTOCONNECT:
- result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
+ result = Curl_protocol_connect(data->conn, &protocol_connect);
if(!result && !protocol_connect)
/* switch to waiting state */
multistate(data, CURLM_STATE_PROTOCONNECT);
else if(!result) {
/* protocol connect has completed, go WAITDO or DO */
- multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
- CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
stream_error = TRUE;
}
break;
case CURLM_STATE_PROTOCONNECT:
/* protocol-specific connect phase */
- result = Curl_protocol_connecting(data->easy_conn, &protocol_connect);
+ result = Curl_protocol_connecting(data->conn, &protocol_connect);
if(!result && protocol_connect) {
/* after the connect has completed, go WAITDO or DO */
- multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
- CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
stream_error = TRUE;
}
break;
- case CURLM_STATE_WAITDO:
- /* Wait for our turn to DO when we're pipelining requests */
- if(Curl_pipeline_checkget_write(data, data->easy_conn)) {
- /* Grabbed the channel */
- multistate(data, CURLM_STATE_DO);
- rc = CURLM_CALL_MULTI_PERFORM;
- }
- break;
-
case CURLM_STATE_DO:
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
- connkeep(data->easy_conn, "CONNECT_ONLY");
+ connkeep(data->conn, "CONNECT_ONLY");
multistate(data, CURLM_STATE_DONE);
result = CURLE_OK;
rc = CURLM_CALL_MULTI_PERFORM;
}
else {
/* Perform the protocol's DO action */
- result = multi_do(&data->easy_conn, &dophase_done);
+ result = multi_do(data, &dophase_done);
- /* When multi_do() returns failure, data->easy_conn might be NULL! */
+ /* When multi_do() returns failure, data->conn might be NULL! */
if(!result) {
if(!dophase_done) {
+#ifndef CURL_DISABLE_FTP
/* some steps needed for wildcard matching */
if(data->state.wildcardmatch) {
struct WildcardData *wc = &data->wildcard;
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
- multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multi_done(data, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
break;
}
}
+#endif
/* DO was not completed in one function call, we must continue
DOING... */
multistate(data, CURLM_STATE_DOING);
@@ -1685,7 +1586,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* after DO, go DO_DONE... or DO_MORE */
- else if(data->easy_conn->bits.do_more) {
+ else if(data->conn->bits.do_more) {
/* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
multistate(data, CURLM_STATE_DO_MORE);
@@ -1698,7 +1599,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_SEND_ERROR == result) &&
- data->easy_conn->bits.reuse) {
+ data->conn->bits.reuse) {
/*
* In this situation, a connection that we were trying to use
* may have unexpectedly died. If possible, send the connection
@@ -1708,7 +1609,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
followtype follow = FOLLOW_NONE;
CURLcode drc;
- drc = Curl_retry_request(data->easy_conn, &newurl);
+ drc = Curl_retry_request(data->conn, &newurl);
if(drc) {
/* a failure here pretty much implies an out of memory */
result = drc;
@@ -1716,7 +1617,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
Curl_posttransfer(data);
- drc = multi_done(&data->easy_conn, result, FALSE);
+ drc = multi_done(data, result, FALSE);
/* When set to retry the connection, we must to go back to
* the CONNECT state */
@@ -1748,8 +1649,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- if(data->easy_conn)
- multi_done(&data->easy_conn, result, FALSE);
+ if(data->conn)
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
}
@@ -1757,12 +1658,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_DOING:
/* we continue DOING until the DO phase is complete */
- result = Curl_protocol_doing(data->easy_conn,
+ DEBUGASSERT(data->conn);
+ result = Curl_protocol_doing(data->conn,
&dophase_done);
if(!result) {
if(dophase_done) {
/* after DO, go DO_DONE or DO_MORE */
- multistate(data, data->easy_conn->bits.do_more?
+ multistate(data, data->conn->bits.do_more?
CURLM_STATE_DO_MORE:
CURLM_STATE_DO_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1771,7 +1673,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, FALSE);
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
break;
@@ -1780,10 +1682,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/*
* When we are connected, DO MORE and then go DO_DONE
*/
- result = multi_do_more(data->easy_conn, &control);
+ DEBUGASSERT(data->conn);
+ result = multi_do_more(data->conn, &control);
- /* No need to remove this handle from the send pipeline here since that
- is done in multi_done() */
if(!result) {
if(control) {
/* if positive, advance to DO_DONE
@@ -1800,46 +1701,38 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, FALSE);
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
break;
case CURLM_STATE_DO_DONE:
- /* Move ourselves from the send to recv pipeline */
- Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
-
- if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
+ DEBUGASSERT(data->conn);
+ if(data->conn->bits.multiplex)
/* Check if we can move pending requests to send pipe */
- process_pending_handles(multi); /* pipelined/multiplexed */
+ process_pending_handles(multi); /* multiplexed */
/* Only perform the transfer if there's a good socket to work with.
Having both BAD is a signal to skip immediately to DONE */
- if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
- (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
- multistate(data, CURLM_STATE_WAITPERFORM);
+ if((data->conn->sockfd != CURL_SOCKET_BAD) ||
+ (data->conn->writesockfd != CURL_SOCKET_BAD))
+ multistate(data, CURLM_STATE_PERFORM);
else {
+#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch &&
- ((data->easy_conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
- data->wildcard.state = CURLWC_DONE;
+ ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
+ data->wildcard.state = CURLWC_DONE;
}
+#endif
multistate(data, CURLM_STATE_DONE);
}
rc = CURLM_CALL_MULTI_PERFORM;
break;
- case CURLM_STATE_WAITPERFORM:
- /* Wait for our turn to PERFORM */
- if(Curl_pipeline_checkget_read(data, data->easy_conn)) {
- /* Grabbed the channel */
- multistate(data, CURLM_STATE_PERFORM);
- rc = CURLM_CALL_MULTI_PERFORM;
- }
- break;
-
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->easy_conn))
+ if(Curl_pgrsUpdate(data->conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
result = Curl_speedcheck(data, now);
@@ -1909,24 +1802,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
- result = Curl_readwrite(data->easy_conn, data, &done, &comeback);
-
- k = &data->req;
-
- if(!(k->keepon & KEEP_RECV))
- /* We're done receiving */
- Curl_pipeline_leave_read(data->easy_conn);
-
- if(!(k->keepon & KEEP_SEND))
- /* We're done sending */
- Curl_pipeline_leave_write(data->easy_conn);
+ result = Curl_readwrite(data->conn, data, &done, &comeback);
if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* 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->easy_conn, &newurl);
+ CURLcode ret = Curl_retry_request(data->conn, &newurl);
if(!ret)
retry = (newurl)?TRUE:FALSE;
else if(!result)
@@ -1939,6 +1822,27 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
done = TRUE;
}
}
+ else if((CURLE_HTTP2_STREAM == result) &&
+ Curl_h2_http_1_1_error(data->conn)) {
+ CURLcode ret = Curl_retry_request(data->conn, &newurl);
+
+ if(!ret) {
+ infof(data, "Downgrades to HTTP/1.1!\n");
+ data->set.httpversion = CURL_HTTP_VERSION_1_1;
+ /* clear the error message bit too as we ignore the one we got */
+ data->state.errorbuf = FALSE;
+ if(!newurl)
+ /* typically for HTTP_1_1_REQUIRED error on first flight */
+ newurl = strdup(data->change.url);
+ /* if we are to retry, set the result to OK and consider the request
+ as done */
+ retry = TRUE;
+ result = CURLE_OK;
+ done = TRUE;
+ }
+ else
+ result = ret;
+ }
if(result) {
/*
@@ -1949,12 +1853,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* happened in the data connection.
*/
- if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) &&
+ if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
result != CURLE_HTTP2_STREAM)
- streamclose(data->easy_conn, "Transfer returned error");
+ streamclose(data->conn, "Transfer returned error");
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
}
else if(done) {
followtype follow = FOLLOW_NONE;
@@ -1962,13 +1866,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
- /* we're no longer receiving */
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
-
- /* expire the new receiving pipeline head */
- if(data->easy_conn->recv_pipe.head)
- Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
-
/* 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) {
@@ -1982,13 +1879,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else
follow = FOLLOW_RETRY;
- result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ (void)multi_done(data, CURLE_OK, FALSE);
+ /* multi_done() might return CURLE_GOT_NOTHING */
+ result = Curl_follow(data, newurl, follow);
if(!result) {
- result = Curl_follow(data, newurl, follow);
- if(!result) {
- multistate(data, CURLM_STATE_CONNECT);
- rc = CURLM_CALL_MULTI_PERFORM;
- }
+ multistate(data, CURLM_STATE_CONNECT);
+ rc = CURLM_CALL_MULTI_PERFORM;
}
free(newurl);
}
@@ -2005,7 +1901,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
free(newurl);
if(result) {
stream_error = TRUE;
- result = multi_done(&data->easy_conn, result, TRUE);
+ result = multi_done(data, result, TRUE);
}
}
@@ -2024,33 +1920,31 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* this state is highly transient, so run another loop after this */
rc = CURLM_CALL_MULTI_PERFORM;
- if(data->easy_conn) {
+ if(data->conn) {
CURLcode res;
- /* Remove ourselves from the receive pipeline, if we are there. */
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
-
- if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
+ if(data->conn->bits.multiplex)
/* Check if we can move pending requests to connection */
- process_pending_handles(multi); /* pipelined/multiplexing */
+ process_pending_handles(multi); /* multiplexing */
/* post-transfer command */
- res = multi_done(&data->easy_conn, result, FALSE);
+ res = multi_done(data, result, FALSE);
/* allow a previously set error code take precedence */
if(!result)
result = res;
/*
- * If there are other handles on the pipeline, multi_done won't set
- * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
+ * 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
*/
- if(data->easy_conn)
- data->easy_conn = NULL;
+ if(data->conn)
+ detach_connnection(data);
}
+#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch) {
if(data->wildcard.state != CURLWC_DONE) {
/* if a wildcard is set and we are not ending -> lets start again
@@ -2059,7 +1953,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
}
}
-
+#endif
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the multi_done() returned! */
multistate(data, CURLM_STATE_COMPLETED);
@@ -2090,23 +1984,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* connection */
- if(data->easy_conn) {
- /* if this has a connection, unsubscribe from the pipelines */
- Curl_pipeline_leave_write(data->easy_conn);
- Curl_pipeline_leave_read(data->easy_conn);
- Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe);
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
-
+ if(data->conn) {
if(stream_error) {
/* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
/* disconnect properly */
- Curl_disconnect(data, data->easy_conn, dead_connection);
+ Curl_disconnect(data, data->conn, dead_connection);
- /* This is where we make sure that the easy_conn pointer is reset.
+ /* This is where we make sure that the conn pointer is reset.
We don't have to do this in every case block above where a
failure is detected */
- data->easy_conn = NULL;
+ detach_connnection(data);
}
}
else if(data->mstate == CURLM_STATE_CONNECT) {
@@ -2118,11 +2006,11 @@ 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->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
+ else if(data->conn && Curl_pgrsUpdate(data->conn)) {
/* aborted due to progress callback return code must close the
connection */
result = CURLE_ABORTED_BY_CALLBACK;
- streamclose(data->easy_conn, "Aborted by callback");
+ streamclose(data->conn, "Aborted by callback");
/* if not yet in DONE state, go there, otherwise COMPLETED */
multistate(data, (data->mstate < CURLM_STATE_DONE)?
@@ -2145,7 +2033,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
msg->extmsg.data.result = result;
rc = multi_addmsg(multi, msg);
- DEBUGASSERT(!data->easy_conn);
+ DEBUGASSERT(!data->conn);
}
multistate(data, CURLM_STATE_MSGSENT);
}
@@ -2225,9 +2113,9 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
data = multi->easyp;
while(data) {
nextdata = data->next;
- if(!data->state.done && data->easy_conn)
+ if(!data->state.done && data->conn)
/* if DONE was never called for this handle */
- (void)multi_done(&data->easy_conn, CURLE_OK, TRUE);
+ (void)multi_done(data, CURLE_OK, TRUE);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(data, data->dns.hostcache);
@@ -2257,11 +2145,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
-
- /* Free the blacklists by setting them to NULL */
- Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
- Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
-
free(multi);
return CURLM_OK;
@@ -2320,6 +2203,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
curl_socket_t s;
int num;
unsigned int curraction;
+ int actions[MAX_SOCKSPEREASYHANDLE];
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
@@ -2336,7 +2220,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
(curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
i++) {
- int action = CURL_POLL_NONE;
+ unsigned int action = CURL_POLL_NONE;
+ unsigned int prevaction = 0;
+ unsigned int comboaction;
+ bool sincebefore = FALSE;
s = socks[i];
@@ -2348,29 +2235,70 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
if(curraction & GETSOCK_WRITESOCK(i))
action |= CURL_POLL_OUT;
+ actions[i] = action;
if(entry) {
- /* yeps, already present so check if it has the same action set */
- if(entry->action == action)
- /* same, continue */
- continue;
+ /* check if new for this transfer */
+ for(i = 0; i< data->numsocks; i++) {
+ if(s == data->sockets[i]) {
+ prevaction = data->actions[i];
+ sincebefore = TRUE;
+ break;
+ }
+ }
+
}
else {
- /* this is a socket we didn't have before, add it! */
- entry = sh_addentry(&multi->sockhash, s, data);
+ /* this is a socket we didn't have before, add it to the hash! */
+ entry = sh_addentry(&multi->sockhash, s);
if(!entry)
/* fatal */
return CURLM_OUT_OF_MEMORY;
}
+ if(sincebefore && (prevaction != action)) {
+ /* Socket was used already, but different action now */
+ if(prevaction & CURL_POLL_IN)
+ entry->readers--;
+ if(prevaction & CURL_POLL_OUT)
+ entry->writers--;
+ if(action & CURL_POLL_IN)
+ entry->readers++;
+ if(action & CURL_POLL_OUT)
+ entry->writers++;
+ }
+ else if(!sincebefore) {
+ /* a new user */
+ entry->users++;
+ if(action & CURL_POLL_IN)
+ entry->readers++;
+ if(action & CURL_POLL_OUT)
+ entry->writers++;
+
+ /* add 'data' to the list of handles using this socket! */
+ Curl_llist_insert_next(&entry->list, entry->list.tail,
+ data, &data->sh_queue);
+ }
+
+ comboaction = (entry->writers? CURL_POLL_OUT : 0) |
+ (entry->readers ? CURL_POLL_IN : 0);
+
+#if 0
+ infof(data, "--- Comboaction: %u readers %u writers\n",
+ entry->readers, entry->writers);
+#endif
+ /* check if it has the same action set */
+ if(entry->action == comboaction)
+ /* same, continue */
+ continue;
/* we know (entry != NULL) at this point, see the logic above */
if(multi->socket_cb)
multi->socket_cb(data,
s,
- action,
+ comboaction,
multi->socket_userp,
entry->socketp);
- entry->action = action; /* store the current action state */
+ entry->action = comboaction; /* store the current action state */
}
num = i; /* number of sockets */
@@ -2379,73 +2307,45 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
make sure to detect sockets that are removed */
for(i = 0; i< data->numsocks; i++) {
int j;
+ bool stillused = FALSE;
s = data->sockets[i];
- for(j = 0; j<num; j++) {
+ for(j = 0; j < num; j++) {
if(s == socks[j]) {
/* this is still supervised */
- s = CURL_SOCKET_BAD;
+ stillused = TRUE;
break;
}
}
+ if(stillused)
+ continue;
entry = sh_getentry(&multi->sockhash, s);
+ /* if this is NULL here, the socket has been closed and notified so
+ already by Curl_multi_closed() */
if(entry) {
- /* this socket has been removed. Tell the app to remove it */
- bool remove_sock_from_hash = TRUE;
-
- /* check if the socket to be removed serves a connection which has
- other easy-s in a pipeline. In this case the socket should not be
- removed. */
- struct connectdata *easy_conn = data->easy_conn;
- if(easy_conn) {
- if(easy_conn->recv_pipe.size > 1) {
- /* the handle should not be removed from the pipe yet */
- remove_sock_from_hash = FALSE;
-
- /* Update the sockhash entry to instead point to the next in line
- for the recv_pipe, or the first (in case this particular easy
- isn't already) */
- if(entry->easy == data) {
- if(Curl_recvpipe_head(data, easy_conn))
- entry->easy = easy_conn->recv_pipe.head->next->ptr;
- else
- entry->easy = easy_conn->recv_pipe.head->ptr;
- }
- }
- if(easy_conn->send_pipe.size > 1) {
- /* the handle should not be removed from the pipe yet */
- remove_sock_from_hash = FALSE;
-
- /* Update the sockhash entry to instead point to the next in line
- for the send_pipe, or the first (in case this particular easy
- isn't already) */
- if(entry->easy == data) {
- if(Curl_sendpipe_head(data, easy_conn))
- entry->easy = easy_conn->send_pipe.head->next->ptr;
- else
- entry->easy = easy_conn->send_pipe.head->ptr;
- }
- }
- /* Don't worry about overwriting recv_pipe head with send_pipe_head,
- when action will be asked on the socket (see multi_socket()), the
- head of the correct pipe will be taken according to the
- action. */
- }
-
- if(remove_sock_from_hash) {
- /* in this case 'entry' is always non-NULL */
+ int oldactions = data->actions[i];
+ /* this socket has been removed. Decrease user count */
+ entry->users--;
+ if(oldactions & CURL_POLL_OUT)
+ entry->writers--;
+ if(oldactions & CURL_POLL_IN)
+ entry->readers--;
+ if(!entry->users) {
if(multi->socket_cb)
- multi->socket_cb(data,
- s,
- CURL_POLL_REMOVE,
+ multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp,
entry->socketp);
sh_delentry(&multi->sockhash, s);
}
- } /* if sockhash entry existed */
+ else {
+ /* remove this transfer as a user of this socket */
+ Curl_llist_remove(&entry->list, &data->sh_queue, NULL);
+ }
+ }
} /* for loop over numsocks */
memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
+ memcpy(data->actions, actions, num*sizeof(int));
data->numsocks = num;
return CURLM_OK;
}
@@ -2466,11 +2366,11 @@ void Curl_updatesocket(struct Curl_easy *data)
* socket again and it gets the same file descriptor number.
*/
-void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
+void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
{
- if(conn->data) {
+ if(data) {
/* if there's still an easy handle associated with this connection */
- struct Curl_multi *multi = conn->data->multi;
+ struct Curl_multi *multi = data->multi;
if(multi) {
/* this is set if this connection is part of a handle that is added to
a multi handle, and only then this is necessary */
@@ -2478,7 +2378,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
if(entry) {
if(multi->socket_cb)
- multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
+ multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp,
entry->socketp);
@@ -2585,46 +2485,37 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
and just move on. */
;
else {
+ struct curl_llist *list = &entry->list;
+ struct curl_llist_element *e;
SIGPIPE_VARIABLE(pipe_st);
- data = entry->easy;
-
- if(data->magic != CURLEASY_MAGIC_NUMBER)
- /* bad bad bad bad bad bad bad */
- return CURLM_INTERNAL_ERROR;
-
- /* If the pipeline is enabled, take the handle which is in the head of
- the pipeline. If we should write into the socket, take the send_pipe
- head. If we should read from the socket, take the recv_pipe head. */
- if(data->easy_conn) {
- if((ev_bitmask & CURL_POLL_OUT) &&
- data->easy_conn->send_pipe.head)
- data = data->easy_conn->send_pipe.head->ptr;
- else if((ev_bitmask & CURL_POLL_IN) &&
- data->easy_conn->recv_pipe.head)
- data = data->easy_conn->recv_pipe.head->ptr;
- }
+ /* the socket can be shared by many transfers, iterate */
+ for(e = list->head; e; e = e->next) {
+ data = (struct Curl_easy *)e->ptr;
- if(data->easy_conn &&
- !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
- /* set socket event bitmask if they're not locked */
- data->easy_conn->cselect_bits = ev_bitmask;
+ if(data->magic != CURLEASY_MAGIC_NUMBER)
+ /* bad bad bad bad bad bad bad */
+ return CURLM_INTERNAL_ERROR;
- sigpipe_ignore(data, &pipe_st);
- result = multi_runsingle(multi, now, data);
- sigpipe_restore(&pipe_st);
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they're not locked */
+ data->conn->cselect_bits = ev_bitmask;
- if(data->easy_conn &&
- !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
- /* clear the bitmask only if not locked */
- data->easy_conn->cselect_bits = 0;
+ sigpipe_ignore(data, &pipe_st);
+ result = multi_runsingle(multi, now, data);
+ sigpipe_restore(&pipe_st);
- if(CURLM_OK >= result) {
- /* get the socket(s) and check if the state has been changed since
- last */
- result = singlesocket(multi, data);
- if(result)
- return result;
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* clear the bitmask only if not locked */
+ data->conn->cselect_bits = 0;
+
+ if(CURLM_OK >= result) {
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ result = singlesocket(multi, data);
+ if(result)
+ return result;
+ }
}
/* Now we fall-through and do the timer-based stuff, since we don't want
@@ -2712,7 +2603,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
multi->push_userp = va_arg(param, void *);
break;
case CURLMOPT_PIPELINING:
- multi->pipelining = va_arg(param, long) & CURLPIPE_MULTIPLEX;
+ multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX;
break;
case CURLMOPT_TIMERFUNCTION:
multi->timer_cb = va_arg(param, curl_multi_timer_callback);
@@ -2726,25 +2617,19 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
case CURLMOPT_MAX_HOST_CONNECTIONS:
multi->max_host_connections = va_arg(param, long);
break;
+ case CURLMOPT_MAX_TOTAL_CONNECTIONS:
+ multi->max_total_connections = va_arg(param, long);
+ break;
+ /* options formerly used for pipelining */
case CURLMOPT_MAX_PIPELINE_LENGTH:
- multi->max_pipeline_length = va_arg(param, long);
break;
case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
- multi->content_length_penalty_size = va_arg(param, long);
break;
case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
- multi->chunk_length_penalty_size = va_arg(param, long);
break;
case CURLMOPT_PIPELINING_SITE_BL:
- res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
- &multi->pipelining_site_bl);
break;
case CURLMOPT_PIPELINING_SERVER_BL:
- res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
- &multi->pipelining_server_bl);
- break;
- case CURLMOPT_MAX_TOTAL_CONNECTIONS:
- multi->max_total_connections = va_arg(param, long);
break;
default:
res = CURLM_UNKNOWN_OPTION;
@@ -3059,7 +2944,7 @@ void Curl_expire_clear(struct Curl_easy *data)
}
#ifdef DEBUGBUILD
- infof(data, "Expire cleared\n");
+ infof(data, "Expire cleared (transfer %p)\n", data);
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
@@ -3097,24 +2982,20 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
return multi ? multi->max_total_connections : 0;
}
-curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
-{
- return multi ? multi->content_length_penalty_size : 0;
-}
-
-curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
-{
- return multi ? multi->chunk_length_penalty_size : 0;
-}
+/*
+ * When information about a connection has appeared, call this!
+ */
-struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
+void Curl_multiuse_state(struct connectdata *conn,
+ int bundlestate) /* use BUNDLE_* defines */
{
- return &multi->pipelining_site_bl;
-}
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->bundle);
+ DEBUGASSERT(conn->data);
+ DEBUGASSERT(conn->data->multi);
-struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
-{
- return &multi->pipelining_server_bl;
+ conn->bundle->multiuse = bundlestate;
+ process_pending_handles(conn->data->multi);
}
static void process_pending_handles(struct Curl_multi *multi)
@@ -3132,6 +3013,9 @@ static void process_pending_handles(struct Curl_multi *multi)
/* Make sure that the handle will be processed soonish. */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+ /* mark this as having been in the pending queue */
+ data->state.previouslypending = TRUE;
}
}
@@ -3175,8 +3059,8 @@ void Curl_multi_dump(struct Curl_multi *multi)
continue;
}
fprintf(stderr, "[%s %s] ",
- entry->action&CURL_POLL_IN?"RECVING":"",
- entry->action&CURL_POLL_OUT?"SENDING":"");
+ (entry->action&CURL_POLL_IN)?"RECVING":"",
+ (entry->action&CURL_POLL_OUT)?"SENDING":"");
}
if(data->numsocks)
fprintf(stderr, "\n");
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index ea2bf352d..279379ae0 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -46,18 +46,16 @@ typedef enum {
CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */
CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect
phase */
- CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */
- CURLM_STATE_DO, /* 9 - start send off the request (part 1) */
- CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */
- CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */
- CURLM_STATE_DO_DONE, /* 12 - done sending off request */
- CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */
- CURLM_STATE_PERFORM, /* 14 - transfer data */
- CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */
- CURLM_STATE_DONE, /* 16 - post data transfer operation */
- CURLM_STATE_COMPLETED, /* 17 - operation complete */
- CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */
- CURLM_STATE_LAST /* 19 - not a true state, never use this */
+ CURLM_STATE_DO, /* 8 - start send off the request (part 1) */
+ CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */
+ CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */
+ CURLM_STATE_DO_DONE, /* 11 - done sending off request */
+ CURLM_STATE_PERFORM, /* 12 - transfer data */
+ CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */
+ CURLM_STATE_DONE, /* 14 - post data transfer operation */
+ CURLM_STATE_COMPLETED, /* 15 - operation complete */
+ CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */
+ CURLM_STATE_LAST /* 17 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
@@ -66,7 +64,7 @@ typedef enum {
#define GETSOCK_READABLE (0x00ff)
#define GETSOCK_WRITABLE (0xff00)
-#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX)
+#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
@@ -112,8 +110,8 @@ struct Curl_multi {
same actual socket) */
struct curl_hash sockhash;
- /* pipelining wanted bits (CURLPIPE*) */
- long pipelining;
+ /* multiplexing wanted */
+ bool multiplexing;
bool recheckstate; /* see Curl_multi_connchanged */
@@ -129,24 +127,6 @@ struct Curl_multi {
long max_total_connections; /* if >0, a fixed limit of the maximum number
of connections in total */
- long max_pipeline_length; /* if >0, maximum number of requests in a
- pipeline */
-
- long content_length_penalty_size; /* a connection with a
- content-length bigger than
- this is not considered
- for pipelining */
-
- long chunk_length_penalty_size; /* a connection with a chunk length
- bigger than this is not
- considered for pipelining */
-
- struct curl_llist pipelining_site_bl; /* List of sites that are blacklisted
- from pipelining */
-
- struct curl_llist pipelining_server_bl; /* List of server types that are
- blacklisted from pipelining */
-
/* timer callback and user data pointer for the *socket() API */
curl_multi_timer_callback timer_cb;
void *timer_userp;
diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
index c8fb5ca0d..e8a5e7062 100644
--- a/Utilities/cmcurl/lib/multiif.h
+++ b/Utilities/cmcurl/lib/multiif.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -30,8 +30,10 @@ void Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, time_t milli, expire_id);
void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
-bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
-void Curl_multi_handlePipeBreak(struct Curl_easy *data);
+void Curl_detach_connnection(struct Curl_easy *data);
+void Curl_attach_connnection(struct Curl_easy *data,
+ struct connectdata *conn);
+bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
bool Curl_is_in_callback(struct Curl_easy *easy);
@@ -62,22 +64,11 @@ void Curl_multi_dump(struct Curl_multi *multi);
/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
-/* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */
-curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi);
-
-/* Return the value of the CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE option */
-curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi);
-
-/* Return the value of the CURLMOPT_PIPELINING_SITE_BL option */
-struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi);
-
-/* Return the value of the CURLMOPT_PIPELINING_SERVER_BL option */
-struct curl_llist *Curl_multi_pipelining_server_bl(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_multi_connchanged(struct Curl_multi *multi);
+void Curl_multiuse_state(struct connectdata *conn,
+ int bundlestate); /* use BUNDLE_* defines */
/*
* Curl_multi_closed()
@@ -89,7 +80,7 @@ void Curl_multi_connchanged(struct Curl_multi *multi);
* socket again and it gets the same file descriptor number.
*/
-void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
+void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);
/*
* Add a handle and move it into PERFORM state at once. For pushed streams.
@@ -97,4 +88,12 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn);
+
+CURLMcode Curl_multi_wait(struct Curl_multi *multi,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret,
+ bool *gotsocket); /* if any socket was checked */
+
#endif /* HEADER_CURL_MULTIIF_H */
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
index 1724b35b0..1bd998f9c 100644
--- a/Utilities/cmcurl/lib/netrc.c
+++ b/Utilities/cmcurl/lib/netrc.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -21,6 +21,7 @@
***************************************************************************/
#include "curl_setup.h"
+#ifndef CURL_DISABLE_NETRC
#ifdef HAVE_PWD_H
#include <pwd.h>
@@ -53,6 +54,8 @@ enum host_lookup_state {
int Curl_parsenetrc(const char *host,
char **loginp,
char **passwordp,
+ bool *login_changed,
+ bool *password_changed,
char *netrcfile)
{
FILE *file;
@@ -164,7 +167,7 @@ int Curl_parsenetrc(const char *host,
if(specific_login) {
state_our_login = strcasecompare(login, tok);
}
- else {
+ else if(!login || strcmp(login, tok)) {
if(login_alloc) {
free(login);
login_alloc = FALSE;
@@ -179,7 +182,8 @@ int Curl_parsenetrc(const char *host,
state_login = 0;
}
else if(state_password) {
- if(state_our_login || !specific_login) {
+ if((state_our_login || !specific_login)
+ && (!password || strcmp(password, tok))) {
if(password_alloc) {
free(password);
password_alloc = FALSE;
@@ -211,15 +215,19 @@ int Curl_parsenetrc(const char *host,
out:
if(!retcode) {
+ *login_changed = FALSE;
+ *password_changed = FALSE;
if(login_alloc) {
if(*loginp)
free(*loginp);
*loginp = login;
+ *login_changed = TRUE;
}
if(password_alloc) {
if(*passwordp)
free(*passwordp);
*passwordp = password;
+ *password_changed = TRUE;
}
}
else {
@@ -233,3 +241,5 @@ int Curl_parsenetrc(const char *host,
return retcode;
}
+
+#endif
diff --git a/Utilities/cmcurl/lib/netrc.h b/Utilities/cmcurl/lib/netrc.h
index d980166e6..7f56c4b4d 100644
--- a/Utilities/cmcurl/lib/netrc.h
+++ b/Utilities/cmcurl/lib/netrc.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,15 +22,24 @@
*
***************************************************************************/
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_NETRC
+
/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
int Curl_parsenetrc(const char *host,
char **loginp,
char **passwordp,
+ bool *login_changed,
+ bool *password_changed,
char *filename);
/* Assume: (*passwordp)[0]=0, host[0] != 0.
* If (*loginp)[0] = 0, search for login and password within a machine
* section in the netrc.
* If (*loginp)[0] != 0, search for password within machine and login.
*/
+#else
+/* disabled */
+#define Curl_parsenetrc(a,b,c,d,e,f) 1
+#endif
#endif /* HEADER_CURL_NETRC_H */
diff --git a/Utilities/cmcurl/lib/non-ascii.c b/Utilities/cmcurl/lib/non-ascii.c
index 14143248f..42beaec45 100644
--- a/Utilities/cmcurl/lib/non-ascii.c
+++ b/Utilities/cmcurl/lib/non-ascii.c
@@ -78,7 +78,7 @@ CURLcode Curl_convert_clone(struct Curl_easy *data,
/*
* Curl_convert_to_network() is an internal function for performing ASCII
- * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ * conversions on non-ASCII platforms. It converts the buffer _in place_.
*/
CURLcode Curl_convert_to_network(struct Curl_easy *data,
char *buffer, size_t length)
@@ -144,7 +144,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
/*
* Curl_convert_from_network() is an internal function for performing ASCII
- * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ * conversions on non-ASCII platforms. It converts the buffer _in place_.
*/
CURLcode Curl_convert_from_network(struct Curl_easy *data,
char *buffer, size_t length)
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index c6cb79434..eeab2c7a7 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
- * Copyright (C) 2011 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2019, 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
@@ -196,9 +196,6 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
li->proto = proto;
conn->proto.generic = li;
connkeep(conn, "OpenLDAP default");
- /* TODO:
- * - provide option to choose SASL Binds instead of Simple
- */
return CURLE_OK;
}
@@ -220,8 +217,8 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
ptr = hosturl + 4;
if(conn->handler->flags & PROTOPT_SSL)
*ptr++ = 's';
- snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
- conn->host.name, conn->remote_port);
+ msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
+ conn->host.name, conn->remote_port);
#ifdef CURL_OPENLDAP_DEBUG
static int do_trace = 0;
@@ -414,7 +411,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
return CURLE_OUT_OF_MEMORY;
lr->msgid = msgid;
data->req.protop = lr;
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
return CURLE_OK;
}
@@ -510,8 +507,6 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
lr->nument++;
rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
if(rc < 0) {
- /* TODO: verify that this is really how this return code should be
- handled */
*err = CURLE_RECV_ERROR;
return -1;
}
diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c
index 3d3c00b4f..7ae5eb8cd 100644
--- a/Utilities/cmcurl/lib/parsedate.c
+++ b/Utilities/cmcurl/lib/parsedate.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -82,20 +82,6 @@
#include "warnless.h"
#include "parsedate.h"
-const char * const Curl_wkday[] =
-{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
-static const char * const weekday[] =
-{ "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday", "Sunday" };
-const char * const Curl_month[]=
-{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-struct tzinfo {
- char name[5];
- int offset; /* +/- in minutes */
-};
-
/*
* parsedate()
*
@@ -114,6 +100,22 @@ static int parsedate(const char *date, time_t *output);
#define PARSEDATE_LATER 1
#define PARSEDATE_SOONER 2
+#ifndef CURL_DISABLE_PARSEDATE
+
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday", "Sunday" };
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+struct tzinfo {
+ char name[5];
+ int offset; /* +/- in minutes */
+};
+
/* Here's a bunch of frequently used time zone names. These were supported
by the old getdate parser. */
#define tDAYZONE -60 /* offset for daylight savings time */
@@ -555,6 +557,15 @@ static int parsedate(const char *date, time_t *output)
return PARSEDATE_OK;
}
+#else
+/* disabled */
+static int parsedate(const char *date, time_t *output)
+{
+ (void)date;
+ *output = 0;
+ return PARSEDATE_OK; /* a lie */
+}
+#endif
time_t curl_getdate(const char *p, const time_t *now)
{
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
index 2e93d201f..e9568ee3d 100644
--- a/Utilities/cmcurl/lib/pingpong.c
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -44,7 +44,7 @@
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
-time_t Curl_pp_state_timeout(struct pingpong *pp)
+time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
{
struct connectdata *conn = pp->conn;
struct Curl_easy *data = conn->data;
@@ -62,7 +62,7 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
timeout_ms = response_time -
Curl_timediff(Curl_now(), pp->response); /* spent time */
- if(data->set.timeout) {
+ if(data->set.timeout && !disconnecting) {
/* if timeout is requested, find out how much remaining time we have */
time_t timeout2_ms = data->set.timeout - /* timeout time */
Curl_timediff(Curl_now(), conn->now); /* spent time */
@@ -77,13 +77,14 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
/*
* Curl_pp_statemach()
*/
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+ bool disconnecting)
{
struct connectdata *conn = pp->conn;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
time_t interval_ms;
- time_t timeout_ms = Curl_pp_state_timeout(pp);
+ time_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h
index 5ac8df876..dbe1f8d3d 100644
--- a/Utilities/cmcurl/lib/pingpong.h
+++ b/Utilities/cmcurl/lib/pingpong.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -81,14 +81,15 @@ struct pingpong {
* 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);
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+ bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
-time_t Curl_pp_state_timeout(struct pingpong *pp);
+time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
/***********************************************************************
diff --git a/Utilities/cmcurl/lib/pipeline.c b/Utilities/cmcurl/lib/pipeline.c
deleted file mode 100644
index 8de3babd7..000000000
--- a/Utilities/cmcurl/lib/pipeline.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
- * Copyright (C) 2013 - 2018, 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"
-
-#include <curl/curl.h>
-
-#include "urldata.h"
-#include "url.h"
-#include "progress.h"
-#include "multiif.h"
-#include "pipeline.h"
-#include "sendf.h"
-#include "strcase.h"
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-struct site_blacklist_entry {
- struct curl_llist_element list;
- unsigned short port;
- char hostname[1];
-};
-
-static void site_blacklist_llist_dtor(void *user, void *element)
-{
- struct site_blacklist_entry *entry = element;
- (void)user;
- free(entry);
-}
-
-static void server_blacklist_llist_dtor(void *user, void *element)
-{
- (void)user;
- free(element);
-}
-
-bool Curl_pipeline_penalized(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(data) {
- bool penalized = FALSE;
- curl_off_t penalty_size =
- Curl_multi_content_length_penalty_size(data->multi);
- curl_off_t chunk_penalty_size =
- Curl_multi_chunk_length_penalty_size(data->multi);
- curl_off_t recv_size = -2; /* Make it easy to spot in the log */
-
- /* Find the head of the recv pipe, if any */
- if(conn->recv_pipe.head) {
- struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr;
-
- recv_size = recv_handle->req.size;
-
- if(penalty_size > 0 && recv_size > penalty_size)
- penalized = TRUE;
- }
-
- if(chunk_penalty_size > 0 &&
- (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
- penalized = TRUE;
-
- infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
- CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T
- "), penalized: %s\n",
- conn->connection_id, (void *)conn, recv_size,
- conn->chunk.datasize, penalized?"TRUE":"FALSE");
- return penalized;
- }
- return FALSE;
-}
-
-static CURLcode addHandleToPipeline(struct Curl_easy *data,
- struct curl_llist *pipeline)
-{
- Curl_llist_insert_next(pipeline, pipeline->tail, data,
- &data->pipeline_queue);
- return CURLE_OK;
-}
-
-
-CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
- struct connectdata *conn)
-{
- struct curl_llist_element *sendhead = conn->send_pipe.head;
- struct curl_llist *pipeline;
- CURLcode result;
-
- pipeline = &conn->send_pipe;
-
- result = addHandleToPipeline(handle, pipeline);
- if((conn->bundle->multiuse == BUNDLE_PIPELINING) &&
- (pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head)) {
- /* this is a new one as head, expire it */
- Curl_pipeline_leave_write(conn); /* not in use yet */
- Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
- }
-
-#if 0 /* enable for pipeline debugging */
- print_pipeline(conn);
-#endif
-
- return result;
-}
-
-/* Move this transfer from the sending list to the receiving list.
-
- Pay special attention to the new sending list "leader" as it needs to get
- checked to update what sockets it acts on.
-
-*/
-void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
- struct connectdata *conn)
-{
- struct curl_llist_element *curr;
-
- curr = conn->send_pipe.head;
- while(curr) {
- if(curr->ptr == handle) {
- Curl_llist_move(&conn->send_pipe, curr,
- &conn->recv_pipe, conn->recv_pipe.tail);
-
- if(conn->send_pipe.head) {
- /* Since there's a new easy handle at the start of the send pipeline,
- set its timeout value to 1ms to make it trigger instantly */
- Curl_pipeline_leave_write(conn); /* not used now */
-#ifdef DEBUGBUILD
- infof(conn->data, "%p is at send pipe head B!\n",
- (void *)conn->send_pipe.head->ptr);
-#endif
- Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
- }
-
- /* The receiver's list is not really interesting here since either this
- handle is now first in the list and we'll deal with it soon, or
- another handle is already first and thus is already taken care of */
-
- break; /* we're done! */
- }
- curr = curr->next;
- }
-}
-
-bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
- struct connectdata *conn)
-{
- if(handle->multi) {
- struct curl_llist *blacklist =
- Curl_multi_pipelining_site_bl(handle->multi);
-
- if(blacklist) {
- struct curl_llist_element *curr;
-
- curr = blacklist->head;
- while(curr) {
- struct site_blacklist_entry *site;
-
- site = curr->ptr;
- if(strcasecompare(site->hostname, conn->host.name) &&
- site->port == conn->remote_port) {
- infof(handle, "Site %s:%d is pipeline blacklisted\n",
- conn->host.name, conn->remote_port);
- return TRUE;
- }
- curr = curr->next;
- }
- }
- }
- return FALSE;
-}
-
-CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
- struct curl_llist *list)
-{
- /* Free the old list */
- if(list->size)
- Curl_llist_destroy(list, NULL);
-
- if(sites) {
- Curl_llist_init(list, (curl_llist_dtor) site_blacklist_llist_dtor);
-
- /* Parse the URLs and populate the list */
- while(*sites) {
- char *port;
- struct site_blacklist_entry *entry;
-
- entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites));
- if(!entry) {
- Curl_llist_destroy(list, NULL);
- return CURLM_OUT_OF_MEMORY;
- }
- strcpy(entry->hostname, *sites);
-
- port = strchr(entry->hostname, ':');
- if(port) {
- *port = '\0';
- port++;
- entry->port = (unsigned short)strtol(port, NULL, 10);
- }
- else {
- /* Default port number for HTTP */
- entry->port = 80;
- }
-
- Curl_llist_insert_next(list, list->tail, entry, &entry->list);
- sites++;
- }
- }
-
- return CURLM_OK;
-}
-
-struct blacklist_node {
- struct curl_llist_element list;
- char server_name[1];
-};
-
-bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
- char *server_name)
-{
- if(handle->multi && server_name) {
- struct curl_llist *list =
- Curl_multi_pipelining_server_bl(handle->multi);
-
- struct curl_llist_element *e = list->head;
- while(e) {
- struct blacklist_node *bl = (struct blacklist_node *)e;
- if(strncasecompare(bl->server_name, server_name,
- strlen(bl->server_name))) {
- infof(handle, "Server %s is blacklisted\n", server_name);
- return TRUE;
- }
- e = e->next;
- }
-
- DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
- }
- return FALSE;
-}
-
-CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
- struct curl_llist *list)
-{
- /* Free the old list */
- if(list->size)
- Curl_llist_destroy(list, NULL);
-
- if(servers) {
- Curl_llist_init(list, (curl_llist_dtor) server_blacklist_llist_dtor);
-
- /* Parse the URLs and populate the list */
- while(*servers) {
- struct blacklist_node *n;
- size_t len = strlen(*servers);
-
- n = malloc(sizeof(struct blacklist_node) + len);
- if(!n) {
- Curl_llist_destroy(list, NULL);
- return CURLM_OUT_OF_MEMORY;
- }
- strcpy(n->server_name, *servers);
-
- Curl_llist_insert_next(list, list->tail, n, &n->list);
- servers++;
- }
- }
-
-
- return CURLM_OK;
-}
-
-static bool pipe_head(struct Curl_easy *data,
- struct curl_llist *pipeline)
-{
- if(pipeline) {
- struct curl_llist_element *curr = pipeline->head;
- if(curr)
- return (curr->ptr == data) ? TRUE : FALSE;
- }
- return FALSE;
-}
-
-/* returns TRUE if the given handle is head of the recv pipe */
-bool Curl_recvpipe_head(struct Curl_easy *data,
- struct connectdata *conn)
-{
- return pipe_head(data, &conn->recv_pipe);
-}
-
-/* returns TRUE if the given handle is head of the send pipe */
-bool Curl_sendpipe_head(struct Curl_easy *data,
- struct connectdata *conn)
-{
- return pipe_head(data, &conn->send_pipe);
-}
-
-
-/*
- * Check if the write channel is available and this handle as at the head,
- * then grab the channel and return TRUE.
- *
- * If not available, return FALSE.
- */
-
-bool Curl_pipeline_checkget_write(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(conn->bits.multiplex)
- /* when multiplexing, we can use it at once */
- return TRUE;
-
- if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) {
- /* Grab the channel */
- conn->writechannel_inuse = TRUE;
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- * Check if the read channel is available and this handle as at the head, then
- * grab the channel and return TRUE.
- *
- * If not available, return FALSE.
- */
-
-bool Curl_pipeline_checkget_read(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(conn->bits.multiplex)
- /* when multiplexing, we can use it at once */
- return TRUE;
-
- if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) {
- /* Grab the channel */
- conn->readchannel_inuse = TRUE;
- return TRUE;
- }
- return FALSE;
-}
-
-/*
- * The current user of the pipeline write channel gives it up.
- */
-void Curl_pipeline_leave_write(struct connectdata *conn)
-{
- conn->writechannel_inuse = FALSE;
-}
-
-/*
- * The current user of the pipeline read channel gives it up.
- */
-void Curl_pipeline_leave_read(struct connectdata *conn)
-{
- conn->readchannel_inuse = FALSE;
-}
-
-
-#if 0
-void print_pipeline(struct connectdata *conn)
-{
- struct curl_llist_element *curr;
- struct connectbundle *cb_ptr;
- struct Curl_easy *data = conn->data;
-
- cb_ptr = conn->bundle;
-
- if(cb_ptr) {
- curr = cb_ptr->conn_list->head;
- while(curr) {
- conn = curr->ptr;
- infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
- conn->connection_id,
- (void *)conn,
- conn->send_pipe->size,
- conn->recv_pipe->size);
- curr = curr->next;
- }
- }
-}
-
-#endif
diff --git a/Utilities/cmcurl/lib/pipeline.h b/Utilities/cmcurl/lib/pipeline.h
deleted file mode 100644
index 413ba31a0..000000000
--- a/Utilities/cmcurl/lib/pipeline.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef HEADER_CURL_PIPELINE_H
-#define HEADER_CURL_PIPELINE_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
- * Copyright (C) 2013 - 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.
- *
- * You 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.
- *
- ***************************************************************************/
-
-CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
- struct connectdata *conn);
-void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
- struct connectdata *conn);
-bool Curl_pipeline_penalized(struct Curl_easy *data,
- struct connectdata *conn);
-
-bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
- struct connectdata *conn);
-
-CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
- struct curl_llist *list_ptr);
-
-bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
- char *server_name);
-
-CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
- struct curl_llist *list_ptr);
-
-bool Curl_pipeline_checkget_write(struct Curl_easy *data,
- struct connectdata *conn);
-bool Curl_pipeline_checkget_read(struct Curl_easy *data,
- struct connectdata *conn);
-void Curl_pipeline_leave_write(struct connectdata *conn);
-void Curl_pipeline_leave_read(struct connectdata *conn);
-bool Curl_recvpipe_head(struct Curl_easy *data,
- struct connectdata *conn);
-bool Curl_sendpipe_head(struct Curl_easy *data,
- struct connectdata *conn);
-
-#endif /* HEADER_CURL_PIPELINE_H */
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index 5e0fd2299..c8f3965e4 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -30,6 +30,7 @@
* RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
* RFC5034 POP3 SASL Authentication Mechanism
* RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
* Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
*
***************************************************************************/
@@ -208,7 +209,7 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
/* Are we processing CAPA command responses? */
if(pop3c->state == POP3_CAPA) {
/* Do we have the terminating line? */
- if(len >= 1 && !memcmp(line, ".", 1))
+ if(len >= 1 && line[0] == '.')
/* Treat the response as a success */
*resp = '+';
else
@@ -226,7 +227,7 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
}
/* Do we have a continuation response? */
- if(len >= 1 && !memcmp("+", line, 1)) {
+ if(len >= 1 && line[0] == '+') {
*resp = '*';
return TRUE;
@@ -443,7 +444,7 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)
/* Convert the calculated 16 octet digest into a 32 byte hex string */
for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&secret[2 * i], 3, "%02x", digest[i]);
+ msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
@@ -629,6 +630,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
if(line[i] == '<') {
/* Calculate the length of the timestamp */
size_t timestamplen = len - 1 - i;
+ char *at;
if(!timestamplen)
break;
@@ -642,8 +644,15 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
memcpy(pop3c->apoptimestamp, line + i, timestamplen);
pop3c->apoptimestamp[timestamplen] = '\0';
- /* Store the APOP capability */
- pop3c->authtypes |= POP3_TYPE_APOP;
+ /* If the timestamp does not contain '@' it is not (as required by
+ RFC-1939) conformant to the RFC-822 message id syntax, and we
+ therefore do not use APOP authentication. */
+ at = strchr(pop3c->apoptimestamp, '@');
+ if(!at)
+ Curl_safefree(pop3c->apoptimestamp);
+ else
+ /* Store the APOP capability */
+ pop3c->authtypes |= POP3_TYPE_APOP;
break;
}
}
@@ -904,7 +913,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
if(pop3->transfer == FTPTRANSFER_BODY) {
/* POP3 download */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
if(pp->cache) {
/* The header "cache" contains a bunch of data that is actually body
@@ -1017,19 +1026,20 @@ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&pop3c->pp, FALSE);
+ result = Curl_pp_statemach(&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 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);
+ result = Curl_pp_statemach(&pop3c->pp, TRUE, disconnecting);
return result;
}
@@ -1227,7 +1237,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
if(!pop3_perform_quit(conn))
- (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
+ (void)pop3_block_statemach(conn, TRUE); /* ignore errors on QUIT */
/* Disconnect from the server */
Curl_pp_disconnect(&pop3c->pp);
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index a94668dc2..f586d59b4 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -31,6 +31,7 @@
/* check rate limits within this many recent milliseconds, at minimum. */
#define MIN_RATE_LIMIT_PERIOD 3000
+#ifndef CURL_DISABLE_PROGRESS_METER
/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
byte) */
static void time2str(char *r, curl_off_t seconds)
@@ -44,8 +45,8 @@ static void time2str(char *r, curl_off_t seconds)
if(h <= CURL_OFF_T_C(99)) {
curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
- snprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
- ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
+ msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
+ ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
}
else {
/* this equals to more than 99 hours, switch to a more suitable output
@@ -53,10 +54,10 @@ static void time2str(char *r, curl_off_t seconds)
curl_off_t d = seconds / CURL_OFF_T_C(86400);
h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
if(d <= CURL_OFF_T_C(999))
- snprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
- "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
+ msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
+ "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
else
- snprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
+ msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
}
}
@@ -72,40 +73,40 @@ static char *max5data(curl_off_t bytes, char *max5)
#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
if(bytes < CURL_OFF_T_C(100000))
- snprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
+ msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
/* 'XX.XM' is good as long as we're less than 100 megs */
- snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
- CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
- (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
+ (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
#if (CURL_SIZEOF_CURL_OFF_T > 4)
else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
/* 'XXXXM' is good until we're at 10000MB or above */
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
/* 10000 MB - 100 GB, we show it as XX.XG */
- snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
- CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
- (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
+ (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
/* up to 10000GB, display without decimal: XXXXG */
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
/* up to 10000TB, display without decimal: XXXXT */
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
else
/* up to 10000PB, display without decimal: XXXXP */
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
/* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
can hold, but our data type is signed so 8192PB will be the maximum. */
@@ -113,12 +114,13 @@ static char *max5data(curl_off_t bytes, char *max5)
#else
else
- snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
#endif
return max5;
}
+#endif
/*
@@ -362,17 +364,13 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
}
}
-/*
- * Curl_pgrsUpdate() returns 0 for success or the value returned by the
- * progress callback!
- */
-int Curl_pgrsUpdate(struct connectdata *conn)
+#ifndef CURL_DISABLE_PROGRESS_METER
+static void progress_meter(struct connectdata *conn)
{
struct curltime now;
curl_off_t timespent;
curl_off_t timespent_ms; /* milliseconds */
struct Curl_easy *data = conn->data;
- int nowindex = data->progress.speeder_c% CURR_TIME;
bool shownow = FALSE;
curl_off_t dl = data->progress.downloaded;
curl_off_t ul = data->progress.uploaded;
@@ -399,7 +397,9 @@ int Curl_pgrsUpdate(struct connectdata *conn)
/* Calculations done at most once a second, unless end is reached */
if(data->progress.lastshow != now.tv_sec) {
int countindex; /* amount of seconds stored in the speeder array */
- shownow = TRUE;
+ int nowindex = data->progress.speeder_c% CURR_TIME;
+ if(!(data->progress.flags & PGRS_HIDE))
+ shownow = TRUE;
data->progress.lastshow = now.tv_sec;
@@ -461,8 +461,12 @@ int Curl_pgrsUpdate(struct connectdata *conn)
data->progress.ulspeed + data->progress.dlspeed;
} /* Calculations end */
-
- if(!(data->progress.flags & PGRS_HIDE)) {
+ if(!shownow)
+ /* only show the internal progress meter once per second */
+ return;
+ else {
+ /* If there's no external callback set, use internal code to show
+ progress */
/* progress meter has not been shut off */
char max5[6][10];
curl_off_t dlpercen = 0;
@@ -477,42 +481,6 @@ int Curl_pgrsUpdate(struct connectdata *conn)
curl_off_t dlestimate = 0;
curl_off_t total_estimate;
- if(data->set.fxferinfo) {
- int result;
- /* There's a callback set, call that */
- Curl_set_in_callback(data, true);
- result = data->set.fxferinfo(data->set.progress_client,
- data->progress.size_dl,
- data->progress.downloaded,
- data->progress.size_ul,
- data->progress.uploaded);
- Curl_set_in_callback(data, false);
- if(result)
- failf(data, "Callback aborted");
- return result;
- }
- if(data->set.fprogress) {
- int result;
- /* The older deprecated callback is set, call that */
- Curl_set_in_callback(data, true);
- result = data->set.fprogress(data->set.progress_client,
- (double)data->progress.size_dl,
- (double)data->progress.downloaded,
- (double)data->progress.size_ul,
- (double)data->progress.uploaded);
- Curl_set_in_callback(data, false);
- if(result)
- failf(data, "Callback aborted");
- return result;
- }
-
- if(!shownow)
- /* only show the internal progress meter once per second */
- return 0;
-
- /* If there's no external callback set, use internal code to show
- progress */
-
if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
if(data->state.resume_from) {
fprintf(data->set.err,
@@ -564,9 +532,9 @@ int Curl_pgrsUpdate(struct connectdata *conn)
/* Get the total amount of data expected to get transferred */
total_expected_transfer =
- (data->progress.flags & PGRS_UL_SIZE_KNOWN?
+ ((data->progress.flags & PGRS_UL_SIZE_KNOWN)?
data->progress.size_ul:data->progress.uploaded)+
- (data->progress.flags & PGRS_DL_SIZE_KNOWN?
+ ((data->progress.flags & PGRS_DL_SIZE_KNOWN)?
data->progress.size_dl:data->progress.downloaded);
/* We have transferred this much so far */
@@ -595,13 +563,57 @@ int Curl_pgrsUpdate(struct connectdata *conn)
time_total, /* 8 letters */ /* total time */
time_spent, /* 8 letters */ /* time spent */
time_left, /* 8 letters */ /* time left */
- max5data(data->progress.current_speed, max5[5]) /* current speed */
- );
+ max5data(data->progress.current_speed, max5[5])
+ );
/* we flush the output stream to make it appear as soon as possible */
fflush(data->set.err);
+ } /* don't show now */
+}
+#else
+ /* progress bar disabled */
+#define progress_meter(x)
+#endif
+
- } /* !(data->progress.flags & PGRS_HIDE) */
+/*
+ * Curl_pgrsUpdate() returns 0 for success or the value returned by the
+ * progress callback!
+ */
+int Curl_pgrsUpdate(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ if(!(data->progress.flags & PGRS_HIDE)) {
+ if(data->set.fxferinfo) {
+ int result;
+ /* There's a callback set, call that */
+ Curl_set_in_callback(data, true);
+ result = data->set.fxferinfo(data->set.progress_client,
+ data->progress.size_dl,
+ data->progress.downloaded,
+ data->progress.size_ul,
+ data->progress.uploaded);
+ Curl_set_in_callback(data, false);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+ if(data->set.fprogress) {
+ int result;
+ /* The older deprecated callback is set, call that */
+ Curl_set_in_callback(data, true);
+ result = data->set.fprogress(data->set.progress_client,
+ (double)data->progress.size_dl,
+ (double)data->progress.downloaded,
+ (double)data->progress.size_ul,
+ (double)data->progress.uploaded);
+ Curl_set_in_callback(data, false);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+ }
+ progress_meter(conn);
return 0;
}
diff --git a/Utilities/cmcurl/lib/rand.h b/Utilities/cmcurl/lib/rand.h
index c6fae3553..5deb04161 100644
--- a/Utilities/cmcurl/lib/rand.h
+++ b/Utilities/cmcurl/lib/rand.h
@@ -39,8 +39,11 @@
*/
CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
-/* Same as above but outputs only random lowercase hex characters.
- Does NOT terminate.*/
+/*
+ * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
+ * hexadecimal digits PLUS a zero terminating byte. It must be an odd number
+ * size.
+ */
CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
size_t num);
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index 01dfce640..74cf23244 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -42,16 +42,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-/*
- * TODO (general)
- * -incoming server requests
- * -server CSeq counter
- * -digest authentication
- * -connect through proxy
- * -pipelining?
- */
-
-
#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1])))
#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
@@ -80,8 +70,6 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
bool *readmore);
static CURLcode rtsp_setup_connection(struct connectdata *conn);
-
-bool rtsp_connisdead(struct connectdata *check);
static unsigned int rtsp_conncheck(struct connectdata *check,
unsigned int checks_to_perform);
@@ -147,7 +135,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn)
* Instead, if it is readable, run Curl_connalive() to peek at the socket
* and distinguish between closed and data.
*/
-bool rtsp_connisdead(struct connectdata *check)
+static bool rtsp_connisdead(struct connectdata *check)
{
int sval;
bool ret_val = TRUE;
@@ -238,7 +226,6 @@ static CURLcode rtsp_done(struct connectdata *conn,
if(data->set.rtspreq == RTSPREQ_RECEIVE &&
(conn->proto.rtspc.rtp_channel == -1)) {
infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
- /* TODO CPC: Server -> Client logic here */
}
}
@@ -251,7 +238,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
CURLcode result = CURLE_OK;
Curl_RtspReq rtspreq = data->set.rtspreq;
struct RTSP *rtsp = data->req.protop;
- struct HTTP *http;
Curl_send_buffer *req_buffer;
curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
@@ -270,10 +256,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
*done = TRUE;
- http = &(rtsp->http_wrapper);
- /* Assert that no one has changed the RTSP struct in an evil way */
- DEBUGASSERT((void *)http == (void *)rtsp);
-
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
rtsp->CSeq_recv = 0;
@@ -330,8 +312,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
}
if(rtspreq == RTSPREQ_RECEIVE) {
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
return result;
}
@@ -344,8 +325,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- /* TODO: proxy? */
-
/* Stream URI. Default to server '*' if not specified */
if(data->set.str[STRING_RTSP_STREAM_URI]) {
p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
@@ -599,17 +578,15 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return result;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
- putsize?FIRSTSOCKET:-1,
- putsize?&http->writebytecount:NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;
- if(http->writebytecount) {
+ if(data->req.writebytecount) {
/* if a request-body has been sent off, we make sure this progress is
noted properly */
- Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
}
diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c
index c278406ba..76951548d 100644
--- a/Utilities/cmcurl/lib/security.c
+++ b/Utilities/cmcurl/lib/security.c
@@ -10,7 +10,7 @@
* Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
*
- * Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2001 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* All rights reserved.
*
@@ -120,7 +120,7 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...)
char print_buffer[50];
va_start(args, message);
- vsnprintf(print_buffer, sizeof(print_buffer), message, args);
+ mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
va_end(args);
if(Curl_ftpsend(conn, print_buffer)) {
@@ -142,7 +142,7 @@ socket_read(curl_socket_t fd, void *to, size_t len)
{
char *to_p = to;
CURLcode result;
- ssize_t nread;
+ ssize_t nread = 0;
while(len > 0) {
result = Curl_read_plain(fd, to_p, len, &nread);
@@ -151,7 +151,6 @@ socket_read(curl_socket_t fd, void *to, size_t len)
to_p += nread;
}
else {
- /* FIXME: We are doing a busy wait */
if(result == CURLE_AGAIN)
continue;
return result;
@@ -179,7 +178,6 @@ socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
to_p += written;
}
else {
- /* FIXME: We are doing a busy wait */
if(result == CURLE_AGAIN)
continue;
return result;
@@ -265,13 +263,11 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex,
total_read += bytes_read;
buffer += bytes_read;
}
- /* FIXME: Check for overflow */
return total_read;
}
/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
and negociating with the server. |from| can be NULL. */
-/* FIXME: We don't check for errors nor report any! */
static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
const char *from, int length)
{
@@ -406,18 +402,14 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
if(buf[decoded_len - 1] == '\n')
buf[decoded_len - 1] = '\0';
- /* FIXME: Is |buffer| length always greater than |decoded_len|? */
strcpy(buffer, buf);
free(buf);
return ret_code;
}
-/* FIXME: The error code returned here is never checked. */
static int sec_set_protection_level(struct connectdata *conn)
{
int code;
- char *pbsz;
- static unsigned int buffer_size = 1 << 20; /* 1048576 */
enum protection_level level = conn->request_data_prot;
DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
@@ -433,6 +425,9 @@ static int sec_set_protection_level(struct connectdata *conn)
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;
@@ -508,7 +503,6 @@ static CURLcode choose_mech(struct connectdata *conn)
infof(data, "Trying mechanism %s...\n", mech->name);
ret = ftp_send_command(conn, "AUTH %s", mech->name);
if(ret < 0)
- /* FIXME: This error is too generic but it is OK for now. */
return CURLE_COULDNT_CONNECT;
if(ret/100 != 3) {
@@ -575,7 +569,6 @@ Curl_sec_end(struct connectdata *conn)
conn->in_buffer.data = NULL;
conn->in_buffer.size = 0;
conn->in_buffer.index = 0;
- /* FIXME: Is this really needed? */
conn->in_buffer.eof_flag = 0;
}
conn->sec_complete = 0;
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index d3c10b369..5913ea406 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -237,7 +237,18 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
size_t len;
char print_buffer[2048 + 1];
va_start(ap, fmt);
- vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ /*
+ * Indicate truncation of the input by replacing the last 3 characters
+ * with "...", and transfer the newline over in case the format had one.
+ */
+ if(len >= sizeof(print_buffer)) {
+ len = strlen(fmt);
+ if(fmt[--len] == '\n')
+ msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n");
+ else
+ msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "...");
+ }
va_end(ap);
len = strlen(print_buffer);
Curl_debug(data, CURLINFO_TEXT, print_buffer, len);
@@ -255,7 +266,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
size_t len;
char error[CURL_ERROR_SIZE + 2];
va_start(ap, fmt);
- vsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
+ mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
len = strlen(error);
if(data->set.errorbuffer && !data->state.errorbuf) {
@@ -400,8 +411,9 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
*code = CURLE_AGAIN;
}
else {
+ char buffer[STRERROR_LEN];
failf(conn->data, "Send failure: %s",
- Curl_strerror(conn, err));
+ Curl_strerror(err, buffer, sizeof(buffer)));
conn->data->state.os_errno = err;
*code = CURLE_SEND_ERROR;
}
@@ -465,8 +477,9 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
*code = CURLE_AGAIN;
}
else {
+ char buffer[STRERROR_LEN];
failf(conn->data, "Recv failure: %s",
- Curl_strerror(conn, err));
+ Curl_strerror(err, buffer, sizeof(buffer)));
conn->data->state.os_errno = err;
*code = CURLE_RECV_ERROR;
}
@@ -582,7 +595,10 @@ static CURLcode chop_write(struct connectdata *conn,
size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
if(writebody) {
- size_t wrote = writebody(ptr, 1, chunklen, data->set.out);
+ size_t wrote;
+ Curl_set_in_callback(data, true);
+ wrote = writebody(ptr, 1, chunklen, data->set.out);
+ Curl_set_in_callback(data, false);
if(CURL_WRITEFUNC_PAUSE == wrote) {
if(conn->handler->flags & PROTOPT_NONETWORK) {
@@ -711,10 +727,6 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
char *buffertofill = NULL;
struct Curl_easy *data = conn->data;
- /* if HTTP/1 pipelining is both wanted and possible */
- bool pipelining = Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
- (conn->bundle->multiuse == BUNDLE_PIPELINING);
-
/* 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
us use the correct ssl handle. */
@@ -722,40 +734,13 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
*n = 0; /* reset amount to zero */
- /* If session can pipeline, check connection buffer */
- if(pipelining) {
- size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
- sizerequested);
-
- /* Copy from our master buffer first if we have some unread data there*/
- if(bytestocopy > 0) {
- memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
- conn->read_pos += bytestocopy;
- conn->bits.stream_was_rewound = FALSE;
-
- *n = (ssize_t)bytestocopy;
- return CURLE_OK;
- }
- /* If we come here, it means that there is no data to read from the buffer,
- * so we read from the socket */
- bytesfromsocket = CURLMIN(sizerequested, MASTERBUF_SIZE);
- buffertofill = conn->master_buffer;
- }
- else {
- bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
- buffertofill = buf;
- }
+ bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
+ buffertofill = buf;
nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
if(nread < 0)
return result;
- if(pipelining) {
- memcpy(buf, conn->master_buffer, nread);
- conn->buf_len = nread;
- conn->read_pos = nread;
- }
-
*n += nread;
return CURLE_OK;
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 22956a20f..92cd5b271 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -44,6 +44,7 @@
#include "http2.h"
#include "setopt.h"
#include "multiif.h"
+#include "altsvc.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -60,6 +61,13 @@ CURLcode Curl_setstropt(char **charp, const char *s)
if(s) {
char *str = strdup(s);
+ if(str) {
+ size_t len = strlen(str);
+ if(len > CURL_MAX_INPUT_LENGTH) {
+ free(str);
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
if(!str)
return CURLE_OUT_OF_MEMORY;
@@ -111,12 +119,13 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
-CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
- va_list param)
+static CURLcode vsetopt(struct Curl_easy *data, CURLoption option,
+ va_list param)
{
char *argptr;
CURLcode result = CURLE_OK;
long arg;
+ unsigned long uarg;
curl_off_t bigsize;
switch(option) {
@@ -127,23 +136,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.dns_cache_timeout = arg;
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
-#if 0 /* deprecated */
- /* remember we want this enabled */
- arg = va_arg(param, long);
- data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
-#endif
+ /* deprecated */
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection for proxy */
result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
va_arg(param, char *));
break;
-
+#endif
case CURLOPT_TLS13_CIPHERS:
if(Curl_ssl_tls13_ciphersuites()) {
/* set preferred list of TLS 1.3 cipher suites */
@@ -153,6 +159,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
else
return CURLE_NOT_BUILT_IN;
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_TLS13_CIPHERS:
if(Curl_ssl_tls13_ciphersuites()) {
/* set preferred list of TLS 1.3 cipher suites for proxy */
@@ -162,7 +169,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
else
return CURLE_NOT_BUILT_IN;
break;
-
+#endif
case CURLOPT_RANDOM_FILE:
/*
* This is the path name to a file that contains random data to seed
@@ -270,27 +277,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
- case CURLOPT_FTP_CREATE_MISSING_DIRS:
- /*
- * An FTP 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;
- }
- break;
case CURLOPT_SERVER_RESPONSE_TIMEOUT:
/*
* Option that specifies how quickly an server response must be obtained
@@ -302,6 +288,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
else
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
+#ifndef CURL_DISABLE_TFTP
case CURLOPT_TFTP_NO_OPTIONS:
/*
* Option that prevents libcurl from sending TFTP option requests to the
@@ -318,28 +305,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.tftp_blksize = arg;
break;
- case CURLOPT_DIRLISTONLY:
- /*
- * An option that changes the command to one that asks for a list
- * only, no file info details.
- */
- data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_APPEND:
- /*
- * We want to upload and append to an existing file.
- */
- data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_FTP_FILEMETHOD:
- /*
- * How do access files over FTP.
- */
- arg = va_arg(param, long);
- if((arg < CURLFTPMETHOD_DEFAULT) || (arg > CURLFTPMETHOD_SINGLECWD))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftp_filemethod = (curl_ftpfile)arg;
- break;
+#endif
+#ifndef CURL_DISABLE_NETRC
case CURLOPT_NETRC:
/*
* Parse the $HOME/.netrc file
@@ -356,6 +323,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
va_arg(param, char *));
break;
+#endif
case CURLOPT_TRANSFERTEXT:
/*
* This option was previously named 'FTPASCII'. Renamed to work with
@@ -663,6 +631,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
break;
#ifndef CURL_DISABLE_HTTP
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXYHEADER:
/*
* Set a list with proxy headers to use (or replace internals with)
@@ -676,13 +645,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.proxyheaders = va_arg(param, struct curl_slist *);
break;
-
+#endif
case CURLOPT_HEADEROPT:
/*
* Set header option.
*/
arg = va_arg(param, long);
- data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
+ data->set.sep_headers = (bool)((arg & CURLHEADER_SEPARATE)? TRUE: FALSE);
break;
case CURLOPT_HTTP200ALIASES:
@@ -803,12 +772,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
if(checkprefix("Set-Cookie:", argptr))
/* HTTP Header format line */
Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
- NULL);
+ NULL, TRUE);
else
/* Netscape format line */
Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
- NULL);
+ NULL, TRUE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
free(argptr);
@@ -860,6 +829,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.expect_100_timeout = arg;
break;
+ case CURLOPT_HTTP09_ALLOWED:
+ arg = va_arg(param, unsigned long);
+ if(arg > 1L)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.http09_allowed = arg ? TRUE : FALSE;
+ break;
#endif /* CURL_DISABLE_HTTP */
case CURLOPT_HTTPAUTH:
@@ -878,7 +853,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+ data->state.authhost.iestyle =
+ (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE);
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -961,7 +937,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+ data->state.authproxy.iestyle =
+ (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE);
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1063,7 +1040,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
#endif
-
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_SOCKS5_GSSAPI_SERVICE:
case CURLOPT_PROXY_SERVICE_NAME:
/*
@@ -1072,7 +1049,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
va_arg(param, char *));
break;
-
+#endif
case CURLOPT_SERVICE_NAME:
/*
* Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
@@ -1101,6 +1078,33 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.out = va_arg(param, void *);
break;
+
+ case CURLOPT_DIRLISTONLY:
+ /*
+ * An option that changes the command to one that asks for a list only, no
+ * file info details. Used for FTP, POP3 and SFTP.
+ */
+ data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_APPEND:
+ /*
+ * We want to upload and append to an existing file. Used for FTP and
+ * SFTP.
+ */
+ data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+#ifndef CURL_DISABLE_FTP
+ case CURLOPT_FTP_FILEMETHOD:
+ /*
+ * How do access files over FTP.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLFTPMETHOD_DEFAULT) || (arg > CURLFTPMETHOD_SINGLECWD))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ftp_filemethod = (curl_ftpfile)arg;
+ break;
case CURLOPT_FTPPORT:
/*
* Use FTP PORT, this also specifies which IP address to use
@@ -1137,6 +1141,55 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
+ case CURLOPT_FTP_ACCOUNT:
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_FTPSSLAUTH:
+ /*
+ * Set a specific auth for FTP-SSL transfers.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLFTPAUTH_DEFAULT) || (arg > CURLFTPAUTH_TLS))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ftpsslauth = (curl_ftpauth)arg;
+ break;
+ case CURLOPT_KRBLEVEL:
+ /*
+ * A string that defines the kerberos security level.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
+ va_arg(param, char *));
+ data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
+ break;
+#endif
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
+ /*
+ * 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;
+ }
+ break;
case CURLOPT_READDATA:
/*
* FILE pointer to read the file to be uploaded from. Or possibly
@@ -1204,6 +1257,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.low_speed_time = arg;
break;
+ case CURLOPT_CURLU:
+ /*
+ * pass CURLU to set URL
+ */
+ data->set.uh = va_arg(param, CURLU *);
+ break;
case CURLOPT_URL:
/*
* The URL to fetch.
@@ -1539,6 +1598,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLCERT:
/*
* String that holds file name of the SSL certificate to use for proxy
@@ -1546,6 +1606,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_SSLCERTTYPE:
/*
* String that holds file type of the SSL certificate to use
@@ -1553,6 +1614,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLCERTTYPE:
/*
* String that holds file type of the SSL certificate to use for proxy
@@ -1560,6 +1622,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_SSLKEY:
/*
* String that holds file name of the SSL key to use
@@ -1567,6 +1630,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLKEY:
/*
* String that holds file name of the SSL key to use for proxy
@@ -1574,6 +1638,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_SSLKEYTYPE:
/*
* String that holds file type of the SSL key to use
@@ -1581,6 +1646,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLKEYTYPE:
/*
* String that holds file type of the SSL key to use for proxy
@@ -1588,6 +1654,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_KEYPASSWD:
/*
* String that holds the SSL or SSH private key password.
@@ -1595,6 +1662,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_KEYPASSWD:
/*
* String that holds the SSL private key password for proxy.
@@ -1602,6 +1670,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_SSLENGINE:
/*
* String that holds the SSL crypto engine.
@@ -1628,14 +1697,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
-
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_HAPROXYPROTOCOL:
/*
* Set to send the HAProxy Proxy Protocol header
*/
data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
-
+#endif
case CURLOPT_INTERFACE:
/*
* Set what interface or address/hostname to bind the socket to when
@@ -1662,14 +1731,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.localportrange = curlx_sltosi(arg);
break;
- case CURLOPT_KRBLEVEL:
- /*
- * A string that defines the kerberos security level.
- */
- result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
- va_arg(param, char *));
- data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
- break;
case CURLOPT_GSSAPI_DELEGATION:
/*
* GSS-API credential delegation bitmask
@@ -1687,11 +1748,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifypeer =
+ if(data->conn) {
+ data->conn->ssl_config.verifypeer =
data->set.ssl.primary.verifypeer;
}
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYPEER:
/*
* Enable peer SSL verifying for proxy.
@@ -1700,11 +1762,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
(0 != va_arg(param, long))?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->proxy_ssl_config.verifypeer =
+ if(data->conn) {
+ data->conn->proxy_ssl_config.verifypeer =
data->set.proxy_ssl.primary.verifypeer;
}
break;
+#endif
case CURLOPT_SSL_VERIFYHOST:
/*
* Enable verification of the host name in the peer certificate
@@ -1724,11 +1787,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifyhost =
+ if(data->conn) {
+ data->conn->ssl_config.verifyhost =
data->set.ssl.primary.verifyhost;
}
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYHOST:
/*
* Enable verification of the host name in the peer certificate for proxy
@@ -1748,11 +1812,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->proxy_ssl_config.verifyhost =
+ if(data->conn) {
+ data->conn->proxy_ssl_config.verifyhost =
data->set.proxy_ssl.primary.verifyhost;
}
break;
+#endif
case CURLOPT_SSL_VERIFYSTATUS:
/*
* Enable certificate status verifying.
@@ -1766,8 +1831,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifystatus =
+ if(data->conn) {
+ data->conn->ssl_config.verifystatus =
data->set.ssl.primary.verifystatus;
}
break;
@@ -1825,6 +1890,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#endif
result = CURLE_NOT_BUILT_IN;
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_PINNEDPUBLICKEY:
/*
* Set pinned public key for SSL connection.
@@ -1838,6 +1904,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#endif
result = CURLE_NOT_BUILT_IN;
break;
+#endif
case CURLOPT_CAINFO:
/*
* Set CA info for SSL connection. Specify file name of the CA certificate
@@ -1845,6 +1912,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CAINFO:
/*
* Set CA info SSL connection for proxy. Specify file name of the
@@ -1853,6 +1921,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_CAPATH:
/*
* Set CA path info for SSL connection. Specify directory name of the CA
@@ -1867,6 +1936,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#endif
result = CURLE_NOT_BUILT_IN;
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CAPATH:
/*
* Set CA path info for SSL connection proxy. Specify directory name of the
@@ -1881,6 +1951,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#endif
result = CURLE_NOT_BUILT_IN;
break;
+#endif
case CURLOPT_CRLFILE:
/*
* Set CRL file info for SSL connection. Specify file name of the CRL
@@ -1889,6 +1960,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CRLFILE:
/*
* Set CRL file info for SSL connection for proxy. Specify file name of the
@@ -1897,6 +1969,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
va_arg(param, char *));
break;
+#endif
case CURLOPT_ISSUERCERT:
/*
* Set Issuer certificate file
@@ -1905,13 +1978,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
va_arg(param, char *));
break;
+#ifndef CURL_DISABLE_TELNET
case CURLOPT_TELNETOPTIONS:
/*
* Set a linked list of telnet options
*/
data->set.telnet_options = va_arg(param, struct curl_slist *);
break;
-
+#endif
case CURLOPT_BUFFERSIZE:
/*
* The application kindly asks for a differently sized receive buffer.
@@ -2064,27 +2138,21 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
case CURLOPT_SSL_OPTIONS:
arg = va_arg(param, long);
- data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.ssl.enable_beast =
+ (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_OPTIONS:
arg = va_arg(param, long);
- data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.proxy_ssl.enable_beast =
+ (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
break;
-
#endif
- case CURLOPT_FTPSSLAUTH:
- /*
- * Set a specific auth for FTP-SSL transfers.
- */
- arg = va_arg(param, long);
- if((arg < CURLFTPAUTH_DEFAULT) || (arg > CURLFTPAUTH_TLS))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftpsslauth = (curl_ftpauth)arg;
- break;
+#endif
case CURLOPT_IPRESOLVE:
arg = va_arg(param, long);
if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
@@ -2110,11 +2178,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
- case CURLOPT_FTP_ACCOUNT:
- result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
- va_arg(param, char *));
- break;
-
case CURLOPT_IGNORE_CONTENT_LENGTH:
data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
@@ -2126,11 +2189,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
- case CURLOPT_FTP_ALTERNATIVE_TO_USER:
- result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
- va_arg(param, char *));
- break;
-
case CURLOPT_SOCKOPTFUNCTION:
/*
* socket callback function: called after socket() but before connect()
@@ -2196,7 +2254,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
break;
-#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
+#ifdef USE_SSH
/* we only include SSH options if explicitly built to support SSH */
case CURLOPT_SSH_AUTH_TYPES:
data->set.ssh_auth_types = va_arg(param, long);
@@ -2225,7 +2283,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
va_arg(param, char *));
break;
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+
case CURLOPT_SSH_KNOWNHOSTS:
/*
* Store the file name to read known hosts from.
@@ -2246,8 +2304,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.ssh_keyfunc_userp = va_arg(param, void *);
break;
-#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
-#endif /* USE_LIBSSH2 */
+
+ case CURLOPT_SSH_COMPRESSION:
+ data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+#endif /* USE_SSH */
case CURLOPT_HTTP_TRANSFER_DECODING:
/*
@@ -2263,6 +2324,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
break;
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
case CURLOPT_NEW_FILE_PERMS:
/*
* Uses these permissions instead of 0644
@@ -2282,17 +2344,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.new_directory_perms = arg;
break;
+#endif
case CURLOPT_ADDRESS_SCOPE:
/*
- * We always get longs when passed plain numericals, but for this value we
- * know that an unsigned int will always hold the value so we blindly
- * typecast to this type
+ * Use this scope id when using IPv6
+ * We always get longs when passed plain numericals so we should check
+ * that the value fits into an unsigned 32 bit integer.
*/
- arg = va_arg(param, long);
- if((arg < 0) || (arg > 0xf))
+ uarg = va_arg(param, unsigned long);
+#if SIZEOF_LONG > 4
+ if(uarg > UINT_MAX)
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.scope_id = curlx_sltoui(arg);
+#endif
+ data->set.scope_id = (unsigned int)uarg;
break;
case CURLOPT_PROTOCOLS:
@@ -2316,7 +2381,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
va_arg(param, char *));
break;
-
+#ifndef CURL_DISABLE_SMTP
case CURLOPT_MAIL_FROM:
/* Set the SMTP mail originator */
result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
@@ -2333,12 +2398,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
/* Set the list of mail recipients */
data->set.mail_rcpt = va_arg(param, struct curl_slist *);
break;
+#endif
case CURLOPT_SASL_IR:
/* Enable/disable SASL initial response */
data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
-
+#ifndef CURL_DISABLE_RTSP
case CURLOPT_RTSP_REQUEST:
{
/*
@@ -2447,7 +2513,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
/* Set the user defined RTP write function */
data->set.fwrite_rtp = va_arg(param, curl_write_callback);
break;
-
+#endif
+#ifndef CURL_DISABLE_FTP
case CURLOPT_WILDCARDMATCH:
data->set.wildcard_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
@@ -2466,6 +2533,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
case CURLOPT_FNMATCH_DATA:
data->set.fnmatch_data = va_arg(param, void *);
break;
+#endif
#ifdef USE_TLS_SRP
case CURLOPT_TLSAUTH_USERNAME:
result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
@@ -2510,6 +2578,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
break;
#endif
+#ifdef USE_ARES
case CURLOPT_DNS_SERVERS:
result = Curl_set_dns_servers(data, va_arg(param, char *));
break;
@@ -2522,7 +2591,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
case CURLOPT_DNS_LOCAL_IP6:
result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
break;
-
+#endif
case CURLOPT_TCP_KEEPALIVE:
data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
@@ -2546,13 +2615,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = CURLE_NOT_BUILT_IN;
#endif
break;
+#ifdef USE_NGHTTP2
case CURLOPT_SSL_ENABLE_NPN:
data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_SSL_ENABLE_ALPN:
data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
-
+#endif
#ifdef USE_UNIX_SOCKETS
case CURLOPT_UNIX_SOCKET_PATH:
data->set.abstract_unix_socket = FALSE;
@@ -2603,33 +2673,75 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
case CURLOPT_SUPPRESS_CONNECT_HEADERS:
data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
break;
- case CURLOPT_SSH_COMPRESSION:
- data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
- break;
case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
arg = va_arg(param, long);
if(arg < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.happy_eyeballs_timeout = arg;
break;
+#ifndef CURL_DISABLE_SHUFFLE_DNS
case CURLOPT_DNS_SHUFFLE_ADDRESSES:
data->set.dns_shuffle_addresses = (0 != va_arg(param, long)) ? TRUE:FALSE;
break;
+#endif
case CURLOPT_DISALLOW_USERNAME_IN_URL:
data->set.disallow_username_in_url =
(0 != va_arg(param, long)) ? TRUE : FALSE;
break;
+#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_URL:
result = Curl_setstropt(&data->set.str[STRING_DOH],
va_arg(param, char *));
data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
break;
+#endif
case CURLOPT_UPKEEP_INTERVAL_MS:
arg = va_arg(param, long);
if(arg < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.upkeep_interval_ms = arg;
break;
+ case CURLOPT_MAXAGE_CONN:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.maxage_conn = arg;
+ break;
+ case CURLOPT_TRAILERFUNCTION:
+#ifndef CURL_DISABLE_HTTP
+ data->set.trailer_callback = va_arg(param, curl_trailer_callback);
+#endif
+ break;
+ case CURLOPT_TRAILERDATA:
+#ifndef CURL_DISABLE_HTTP
+ data->set.trailer_data = va_arg(param, void *);
+#endif
+ break;
+#ifdef USE_ALTSVC
+ case CURLOPT_ALTSVC:
+ if(!data->asi) {
+ data->asi = Curl_altsvc_init();
+ if(!data->asi)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ argptr = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr);
+ if(result)
+ return result;
+ (void)Curl_altsvc_load(data->asi, argptr);
+ break;
+ case CURLOPT_ALTSVC_CTRL:
+ if(!data->asi) {
+ data->asi = Curl_altsvc_init();
+ if(!data->asi)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ arg = va_arg(param, long);
+ result = Curl_altsvc_ctrl(data->asi, arg);
+ if(result)
+ return result;
+ break;
+#endif
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
@@ -2658,7 +2770,7 @@ CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
va_start(arg, tag);
- result = Curl_vsetopt(data, tag, arg);
+ result = vsetopt(data, tag, arg);
va_end(arg);
return result;
diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h
index 800f9d3b4..3960a139d 100644
--- a/Utilities/cmcurl/lib/sigpipe.h
+++ b/Utilities/cmcurl/lib/sigpipe.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -23,7 +23,8 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL)
+#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && \
+ (defined(USE_OPENSSL) || defined(USE_MBEDTLS))
#include <signal.h>
struct sigpipe_ignore {
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index e4f266e19..76c99a230 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -947,15 +947,10 @@ static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
static CURLcode smb_do(struct connectdata *conn, bool *done)
{
struct smb_conn *smbc = &conn->proto.smbc;
- struct smb_request *req = conn->data->req.protop;
*done = FALSE;
if(smbc->share) {
- req->path = strchr(smbc->share, '\0');
- if(req->path) {
- req->path++;
- return CURLE_OK;
- }
+ return CURLE_OK;
}
return CURLE_URL_MALFORMAT;
}
@@ -964,6 +959,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
+ struct smb_request *req = data->req.protop;
struct smb_conn *smbc = &conn->proto.smbc;
char *path;
char *slash;
@@ -992,6 +988,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
/* Parse the path for the file path converting any forward slashes into
backslashes */
*slash++ = 0;
+ req->path = slash;
for(; *slash; slash++) {
if(*slash == '/')
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 587562306..4a3462b84 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -28,6 +28,7 @@
* RFC4954 SMTP Authentication
* RFC5321 SMTP protocol
* RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
* Draft SMTP URL Interface <draft-earhart-url-smtp-00.txt>
* Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
*
@@ -207,8 +208,12 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
+ char tmpline[6];
+
result = TRUE;
- *resp = curlx_sltosi(strtol(line, NULL, 10));
+ memset(tmpline, '\0', sizeof(tmpline));
+ memcpy(tmpline, line, (len == 5 ? 5 : 3));
+ *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
/* Make sure real server never sends internal value */
if(*resp == 1)
@@ -955,7 +960,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* SMTP upload */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
state(conn, SMTP_STOP);
@@ -1080,19 +1085,20 @@ static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&smtpc->pp, FALSE);
+ result = Curl_pp_statemach(&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 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);
+ result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting);
return result;
}
@@ -1213,7 +1219,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
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) {
- eob = strdup(SMTP_EOB + 2);
+ eob = strdup(&SMTP_EOB[2]);
len = SMTP_EOB_LEN - 2;
}
else {
@@ -1247,13 +1253,8 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
state(conn, SMTP_POSTDATA);
- /* Run the state-machine
-
- TODO: when the multi interface is used, this _really_ should be using
- the smtp_multi_statemach function but we have no general support for
- non-blocking DONE operations!
- */
- result = smtp_block_statemach(conn);
+ /* Run the state-machine */
+ result = smtp_block_statemach(conn, FALSE);
}
/* Clear the transfer mode for the next request */
@@ -1360,7 +1361,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
if(!smtp_perform_quit(conn))
- (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
+ (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */
/* Disconnect from the server */
Curl_pp_disconnect(&smtpc->pp);
@@ -1383,7 +1384,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
if(smtp->transfer != FTPTRANSFER_BODY)
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index d2209ad89..d8fcc3bbb 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -54,7 +54,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
ssize_t buffersize, /* max amount to read */
ssize_t *n) /* amount bytes read */
{
- ssize_t nread;
+ ssize_t nread = 0;
ssize_t allread = 0;
int result;
*n = 0;
@@ -155,7 +155,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
Curl_addrinfo *hp = NULL;
int rc;
- rc = Curl_resolv(conn, hostname, remote_port, &dns);
+ rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
return CURLE_COULDNT_RESOLVE_PROXY;
@@ -290,7 +290,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
/* wrong version ? */
if(socksreq[0] != 0) {
failf(data,
- "SOCKS4 reply has wrong version, version should be 4.");
+ "SOCKS4 reply has wrong version, version should be 0.");
return CURLE_COULDNT_CONNECT;
}
@@ -527,12 +527,24 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
len = 0;
socksreq[len++] = 1; /* username/pw subnegotiation version */
socksreq[len++] = (unsigned char) proxy_user_len;
- if(proxy_user && proxy_user_len)
+ if(proxy_user && proxy_user_len) {
+ /* 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;
+ }
memcpy(socksreq + len, proxy_user, proxy_user_len);
+ }
len += proxy_user_len;
socksreq[len++] = (unsigned char) proxy_password_len;
- if(proxy_password && proxy_password_len)
+ if(proxy_password && proxy_password_len) {
+ /* 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;
+ }
memcpy(socksreq + len, proxy_password, proxy_password_len);
+ }
len += proxy_password_len;
code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
@@ -597,7 +609,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
else {
struct Curl_dns_entry *dns;
Curl_addrinfo *hp = NULL;
- int rc = Curl_resolv(conn, hostname, remote_port, &dns);
+ int rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
return CURLE_COULDNT_RESOLVE_HOST;
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index 96948ac4b..65294bbeb 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, 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
@@ -151,8 +151,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_OUT_OF_MEMORY;
service.length = serviceptr_length +
strlen(conn->socks_proxy.host.name) + 1;
- snprintf(service.value, service.length + 1, "%s@%s",
- serviceptr, conn->socks_proxy.host.name);
+ msnprintf(service.value, service.length + 1, "%s@%s",
+ serviceptr, conn->socks_proxy.host.name);
gss_major_status = gss_import_name(&gss_minor_status, &service,
GSS_C_NT_HOSTBASED_SERVICE, &server);
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index 34699d374..57027ef68 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -51,8 +51,9 @@ static int check_sspi_err(struct connectdata *conn,
status != SEC_I_COMPLETE_AND_CONTINUE &&
status != SEC_I_COMPLETE_NEEDED &&
status != SEC_I_CONTINUE_NEEDED) {
+ char buffer[STRERROR_LEN];
failf(conn->data, "SSPI error: %s failed: %s", function,
- Curl_sspi_strerror(conn, status));
+ Curl_sspi_strerror(status, buffer, sizeof(buffer)));
return 1;
}
return 0;
@@ -107,9 +108,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
strlen(conn->socks_proxy.host.name) + 2);
if(!service_name)
return CURLE_OUT_OF_MEMORY;
- snprintf(service_name, service_length +
- strlen(conn->socks_proxy.host.name) + 2, "%s/%s",
- service, conn->socks_proxy.host.name);
+ msnprintf(service_name, service_length +
+ strlen(conn->socks_proxy.host.name) + 2, "%s/%s",
+ service, conn->socks_proxy.host.name);
}
input_desc.cBuffers = 1;
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
index baf07e00d..0f5fcd1e8 100644
--- a/Utilities/cmcurl/lib/splay.c
+++ b/Utilities/cmcurl/lib/splay.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1997 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1997 - 2019, 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
@@ -198,7 +198,7 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
/* Deletes the very node we point out from the tree if it's there. Stores a
* pointer to the new resulting tree in 'newroot'.
*
- * Returns zero on success and non-zero on errors! TODO: document error codes.
+ * Returns zero on success and non-zero on errors!
* When returning error, it does not touch the 'newroot' pointer.
*
* NOTE: when the last node of the tree is removed, there's no tree left so
diff --git a/Utilities/cmcurl/lib/ssh-libssh.c b/Utilities/cmcurl/lib/ssh-libssh.c
index 7d590891c..6cfd6bda8 100644
--- a/Utilities/cmcurl/lib/ssh-libssh.c
+++ b/Utilities/cmcurl/lib/ssh-libssh.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2017 - 2018 Red Hat, Inc.
+ * Copyright (C) 2017 - 2019 Red Hat, Inc.
*
* Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
* Robert Kolcun, Andreas Schneider
@@ -95,6 +95,13 @@
#include "memdebug.h"
#include "curl_path.h"
+/* A recent macro provided by libssh. Or make our own. */
+#ifndef SSH_STRING_FREE_CHAR
+/* !checksrc! disable ASSIGNWITHINCONDITION 1 */
+#define SSH_STRING_FREE_CHAR(x) \
+ do { if((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
+#endif
+
/* Local functions: */
static CURLcode myssh_connect(struct connectdata *conn, bool *done);
static CURLcode myssh_multi_statemach(struct connectdata *conn,
@@ -549,6 +556,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
struct Curl_easy *data = conn->data;
struct SSHPROTO *protop = data->req.protop;
struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc = SSH_NO_ERROR, err;
char *new_readdir_line;
int seekerr = CURL_SEEKFUNC_OK;
@@ -792,7 +800,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
- conn->sockfd = ssh_get_fd(sshc->ssh_session);
+ conn->sockfd = sock;
conn->writesockfd = CURL_SOCKET_BAD;
if(conn->handler->protocol == CURLPROTO_SFTP) {
@@ -1192,7 +1200,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -1342,8 +1350,8 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
- snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
- sshc->readdir_filename);
+ msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
+ sshc->readdir_filename);
state(conn, SSH_SFTP_READDIR_LINK);
break;
@@ -1406,12 +1414,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
}
sshc->readdir_line = new_readdir_line;
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen,
- " -> %s",
- sshc->readdir_filename);
+ sshc->readdir_currLen += msnprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen,
+ " -> %s",
+ sshc->readdir_filename);
sftp_attributes_free(sshc->readdir_link_attrs);
sshc->readdir_link_attrs = NULL;
@@ -1421,10 +1429,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
state(conn, SSH_SFTP_READDIR_BOTTOM);
/* FALLTHROUGH */
case SSH_SFTP_READDIR_BOTTOM:
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen, "\n");
+ sshc->readdir_currLen += msnprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen, "\n");
result = Curl_client_write(conn, CLIENTWRITE_BODY,
sshc->readdir_line,
sshc->readdir_currLen);
@@ -1454,7 +1462,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
sshc->sftp_dir = NULL;
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
state(conn, SSH_STOP);
break;
@@ -1595,13 +1603,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded\n");
state(conn, SSH_STOP);
break;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
- FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
@@ -1661,7 +1668,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
sshc->sftp_session = NULL;
}
- Curl_safefree(sshc->homedir);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
conn->data->state.most_recent_ftp_entrypath = NULL;
state(conn, SSH_SESSION_DISCONNECT);
@@ -1723,8 +1730,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
}
/* upload data */
- Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
- FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -1767,8 +1773,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
/* download data */
bytecount = ssh_scp_request_get_size(sshc->scp_session);
data->req.maxdownload = (curl_off_t) bytecount;
- Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1,
- NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
@@ -1829,7 +1834,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
ssh_disconnect(sshc->ssh_session);
- Curl_safefree(sshc->homedir);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
conn->data->state.most_recent_ftp_entrypath = NULL;
state(conn, SSH_SESSION_FREE);
@@ -1866,14 +1871,11 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(sshc->rsa_pub);
Curl_safefree(sshc->rsa);
-
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
-
- Curl_safefree(sshc->homedir);
-
Curl_safefree(sshc->readdir_line);
Curl_safefree(sshc->readdir_linkPath);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
/* the code we are about to return */
result = sshc->actualcode;
@@ -1944,14 +1946,13 @@ static int myssh_getsock(struct connectdata *conn,
static void myssh_block2waitfor(struct connectdata *conn, bool block)
{
struct ssh_conn *sshc = &conn->proto.sshc;
- int dir;
/* If it didn't block, or nothing was returned by ssh_get_poll_flags
* have the original set */
conn->waitfor = sshc->orig_waitfor;
if(block) {
- dir = ssh_get_poll_flags(sshc->ssh_session);
+ int dir = ssh_get_poll_flags(sshc->ssh_session);
if(dir & SSH_READ_PENDING) {
/* translate the libssh define bits into our own bit defines */
conn->waitfor = KEEP_RECV;
@@ -2010,9 +2011,7 @@ static CURLcode myssh_block_statemach(struct connectdata *conn,
}
if(!result && block) {
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- curl_socket_t fd_read = CURL_SOCKET_BAD;
- fd_read = sock;
+ curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
/* wait for the socket to become ready */
(void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
@@ -2048,8 +2047,8 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
{
struct ssh_conn *ssh;
CURLcode result;
+ 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)
@@ -2076,6 +2075,8 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
return CURLE_FAILED_INIT;
}
+ ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
+
if(conn->user) {
infof(data, "User: %s\n", conn->user);
ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
@@ -2101,8 +2102,8 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
ssh->pubkey = NULL;
if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
- rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
- &ssh->pubkey);
+ int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
+ &ssh->pubkey);
if(rc != SSH_OK) {
failf(data, "Could not load public key file");
/* ignore */
@@ -2222,12 +2223,7 @@ static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
struct SSHPROTO *protop = conn->data->req.protop;
if(!status) {
- /* run the state-machine
-
- TODO: when the multi interface is used, this _really_ should be using
- the ssh_multi_statemach function but we have no general support for
- non-blocking DONE operations!
- */
+ /* run the state-machine */
result = myssh_block_statemach(conn, FALSE);
}
else
@@ -2390,13 +2386,9 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode 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(!status && !premature && conn->data->set.postquote &&
- !conn->bits.retry) {
+ if(!premature && conn->data->set.postquote && !conn->bits.retry)
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
- state(conn, SSH_SFTP_CLOSE);
- }
- else
- state(conn, SSH_SFTP_CLOSE);
+ state(conn, SSH_SFTP_CLOSE);
}
return myssh_done(conn, status);
}
diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c
index da896196f..a265c3c9a 100644
--- a/Utilities/cmcurl/lib/ssh.c
+++ b/Utilities/cmcurl/lib/ssh.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -81,11 +81,11 @@
#include "multiif.h"
#include "select.h"
#include "warnless.h"
+#include "curl_path.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
-#include "curl_path.h"
#include "memdebug.h"
#if LIBSSH2_VERSION_NUM >= 0x010206
@@ -290,10 +290,6 @@ static CURLcode libssh2_session_error_to_CURLE(int err)
return CURLE_AGAIN;
}
- /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
- error code, and possibly add a few new SSH-related one. We must however
- not return or even depend on libssh2 errors in the public libcurl API */
-
return CURLE_SSH;
}
@@ -591,15 +587,15 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn)
struct Curl_easy *data = conn->data;
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
char md5buffer[33];
- int i;
const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_MD5);
if(fingerprint) {
/* The fingerprint points to static storage (!), don't free() it. */
+ int i;
for(i = 0; i < 16; i++)
- snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+ msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
}
@@ -667,7 +663,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc) {
- failf(data, "Failure establishing ssh session");
+ char *err_msg = NULL;
+ (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);
sshc->actualcode = CURLE_FAILED_INIT;
break;
@@ -734,18 +733,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
(strstr(sshc->authlist, "publickey") != NULL)) {
- char *home = NULL;
bool out_of_memory = FALSE;
sshc->rsa_pub = sshc->rsa = NULL;
- /* To ponder about: should really the lib be messing about with the
- HOME environment variable etc? */
- home = curl_getenv("HOME");
-
if(data->set.str[STRING_SSH_PRIVATE_KEY])
sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
else {
+ /* To ponder about: should really the lib be messing about with the
+ HOME environment variable etc? */
+ char *home = curl_getenv("HOME");
+
/* If no private key file is specified, try some common paths. */
if(home) {
/* Try ~/.ssh first. */
@@ -761,6 +759,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(sshc->rsa);
}
}
+ free(home);
}
if(!out_of_memory && !sshc->rsa) {
/* Nothing found; try the current dir. */
@@ -792,7 +791,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
if(out_of_memory || sshc->rsa == NULL) {
- free(home);
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->rsa_pub);
state(conn, SSH_SESSION_FREE);
@@ -804,8 +802,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if(!sshc->passphrase)
sshc->passphrase = "";
- free(home);
-
if(sshc->rsa_pub)
infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
@@ -1805,7 +1801,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -1999,8 +1995,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
- snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
- sshc->readdir_filename);
+ msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+ sshc->readdir_filename);
state(conn, SSH_SFTP_READDIR_LINK);
break;
}
@@ -2055,21 +2051,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
sshc->readdir_line = new_readdir_line;
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen,
- " -> %s",
- sshc->readdir_filename);
+ sshc->readdir_currLen += msnprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen,
+ " -> %s",
+ sshc->readdir_filename);
state(conn, SSH_SFTP_READDIR_BOTTOM);
break;
case SSH_SFTP_READDIR_BOTTOM:
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen, "\n");
+ sshc->readdir_currLen += msnprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen, "\n");
result = Curl_client_write(conn, CLIENTWRITE_BODY,
sshc->readdir_line,
sshc->readdir_currLen);
@@ -2102,7 +2098,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(sshc->readdir_longentry);
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
state(conn, SSH_STOP);
break;
@@ -2242,13 +2238,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded\n");
state(conn, SSH_STOP);
break;
}
- Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
- FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
@@ -2392,8 +2387,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
/* upload data */
- Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
- FIRSTSOCKET, NULL);
+ Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -2464,7 +2458,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
/* download data */
bytecount = (curl_off_t)sb.st_size;
data->req.maxdownload = (curl_off_t)sb.st_size;
- Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
@@ -2788,9 +2782,12 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
CURLcode result = CURLE_OK;
bool block; /* we store the status and use that to provide a ssh_getsock()
implementation */
-
- result = ssh_statemach_act(conn, &block);
- *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+ do {
+ result = ssh_statemach_act(conn, &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);
return result;
@@ -3061,12 +3058,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
struct SSHPROTO *sftp_scp = conn->data->req.protop;
if(!status) {
- /* run the state-machine
-
- TODO: when the multi interface is used, this _really_ should be using
- the ssh_multi_statemach function but we have no general support for
- non-blocking DONE operations!
- */
+ /* run the state-machine */
result = ssh_block_statemach(conn, FALSE);
}
else
@@ -3219,13 +3211,9 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode 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(!status && !premature && conn->data->set.postquote &&
- !conn->bits.retry) {
+ if(!premature && conn->data->set.postquote && !conn->bits.retry)
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
- state(conn, SSH_SFTP_CLOSE);
- }
- else
- state(conn, SSH_SFTP_CLOSE);
+ state(conn, SSH_SFTP_CLOSE);
}
return ssh_done(conn, status);
}
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 47ef44a66..e273f3765 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2004 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2004 - 2019, 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
@@ -646,20 +646,18 @@ get_winsock_error (int err, char *buf, size_t len)
* We don't do range checking (on systems other than Windows) since there is
* no good reliable and portable way to do it.
*/
-const char *Curl_strerror(struct connectdata *conn, int err)
+const char *Curl_strerror(int err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
DWORD old_win_err = GetLastError();
#endif
int old_errno = errno;
- char *buf, *p;
+ char *p;
size_t max;
- DEBUGASSERT(conn);
DEBUGASSERT(err >= 0);
- buf = conn->syserr_buf;
- max = sizeof(conn->syserr_buf)-1;
+ max = buflen - 1;
*buf = '\0';
#ifdef USE_WINSOCK
@@ -681,7 +679,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
if(!get_winsock_error(err, buf, max) &&
!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
LANG_NEUTRAL, buf, (DWORD)max, NULL))
- snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+ msnprintf(buf, max, "Unknown error %d (%#x)", err, err);
}
#endif
@@ -695,7 +693,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
*/
if(0 != strerror_r(err, buf, max)) {
if('\0' == buf[0])
- snprintf(buf, max, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
/*
@@ -709,7 +707,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
if(msg)
strncpy(buf, msg, max);
else
- snprintf(buf, max, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)
/*
@@ -721,7 +719,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
if(OK == strerror_r(err, buffer))
strncpy(buf, buffer, max);
else
- snprintf(buf, max, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#else
{
@@ -729,7 +727,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
if(msg)
strncpy(buf, msg, max);
else
- snprintf(buf, max, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#endif
@@ -757,7 +755,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
}
#ifdef USE_WINDOWS_SSPI
-const char *Curl_sspi_strerror (struct connectdata *conn, int err)
+const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
DWORD old_win_err = GetLastError();
@@ -768,15 +766,13 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err)
size_t outmax;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char txtbuf[80];
- char msgbuf[sizeof(conn->syserr_buf)];
+ char msgbuf[256];
char *p, *str, *msg = NULL;
bool msg_formatted = FALSE;
#endif
- DEBUGASSERT(conn);
-
- outbuf = conn->syserr_buf;
- outmax = sizeof(conn->syserr_buf)-1;
+ outbuf = buf;
+ outmax = buflen - 1;
*outbuf = '\0';
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -1032,14 +1028,14 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err)
if(err == SEC_E_OK)
strncpy(outbuf, txt, outmax);
else if(err == SEC_E_ILLEGAL_MESSAGE)
- snprintf(outbuf, outmax,
- "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
- "when a fatal SSL/TLS alert is received (e.g. handshake failed). "
- "More detail may be available in the Windows System event log.",
- err);
+ msnprintf(outbuf, outmax,
+ "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
+ "when a fatal SSL/TLS alert is received (e.g. handshake failed)."
+ " More detail may be available in the Windows System event log.",
+ err);
else {
str = txtbuf;
- snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
+ msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
txtbuf[sizeof(txtbuf)-1] = '\0';
#ifdef _WIN32_WCE
@@ -1075,7 +1071,7 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err)
msg = msgbuf;
}
if(msg)
- snprintf(outbuf, outmax, "%s - %s", str, msg);
+ msnprintf(outbuf, outmax, "%s - %s", str, msg);
else
strncpy(outbuf, str, outmax);
}
diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h
index 627273eb2..683b5b4a3 100644
--- a/Utilities/cmcurl/lib/strerror.h
+++ b/Utilities/cmcurl/lib/strerror.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -24,14 +24,11 @@
#include "urldata.h"
-const char *Curl_strerror (struct connectdata *conn, int err);
-
-#ifdef USE_LIBIDN2
-const char *Curl_idn_strerror (struct connectdata *conn, int err);
-#endif
+#define STRERROR_LEN 128 /* a suitable length */
+const char *Curl_strerror(int err, char *buf, size_t buflen);
#ifdef USE_WINDOWS_SSPI
-const char *Curl_sspi_strerror (struct connectdata *conn, int err);
+const char *Curl_sspi_strerror(int err, char *buf, size_t buflen);
#endif
#endif /* HEADER_CURL_STRERROR_H */
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 6b8004e5b..f7f817dd4 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -26,12 +26,94 @@
#include <curl/curl.h>
#include "system_win32.h"
+#include "curl_sspi.h"
#include "warnless.h"
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"
+LARGE_INTEGER Curl_freq;
+bool Curl_isVistaOrGreater;
+
+/* Curl_win32_init() performs win32 global initialization */
+CURLcode Curl_win32_init(long flags)
+{
+ /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
+ is just for Winsock at the moment. Any required win32 initialization
+ should take place after this block. */
+ if(flags & CURL_GLOBAL_WIN32) {
+#ifdef USE_WINSOCK
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int res;
+
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+#error IPV6_requires_winsock2
+#endif
+
+ wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
+ res = WSAStartup(wVersionRequested, &wsaData);
+
+ if(res != 0)
+ /* Tell the user that we couldn't find a usable */
+ /* winsock.dll. */
+ return CURLE_FAILED_INIT;
+
+ /* Confirm that the Windows Sockets DLL supports what we need.*/
+ /* Note that if the DLL supports versions greater */
+ /* than wVersionRequested, it will still return */
+ /* wVersionRequested in wVersion. wHighVersion contains the */
+ /* highest supported version. */
+
+ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+ HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
+ /* Tell the user that we couldn't find a usable */
+
+ /* winsock.dll. */
+ WSACleanup();
+ return CURLE_FAILED_INIT;
+ }
+ /* The Windows Sockets DLL is acceptable. Proceed. */
+ #elif defined(USE_LWIPSOCK)
+ lwip_init();
+ #endif
+ } /* CURL_GLOBAL_WIN32 */
+
+#ifdef USE_WINDOWS_SSPI
+ {
+ CURLcode result = Curl_sspi_global_init();
+ if(result)
+ return result;
+ }
+#endif
+
+ if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL)) {
+ Curl_isVistaOrGreater = TRUE;
+ QueryPerformanceFrequency(&Curl_freq);
+ }
+ else
+ Curl_isVistaOrGreater = FALSE;
+
+ return CURLE_OK;
+}
+
+/* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
+void Curl_win32_cleanup(long init_flags)
+{
+#ifdef USE_WINDOWS_SSPI
+ Curl_sspi_global_cleanup();
+#endif
+
+ if(init_flags & CURL_GLOBAL_WIN32) {
+#ifdef USE_WINSOCK
+ WSACleanup();
+#endif
+ }
+}
+
#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
defined(USE_WINSOCK))
diff --git a/Utilities/cmcurl/lib/system_win32.h b/Utilities/cmcurl/lib/system_win32.h
index 1e772856b..926328a9a 100644
--- a/Utilities/cmcurl/lib/system_win32.h
+++ b/Utilities/cmcurl/lib/system_win32.h
@@ -26,6 +26,12 @@
#if defined(WIN32)
+extern LARGE_INTEGER Curl_freq;
+extern bool Curl_isVistaOrGreater;
+
+CURLcode Curl_win32_init(long flags);
+void Curl_win32_cleanup(long init_flags);
+
/* Version condition */
typedef enum {
VERSION_LESS_THAN,
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index 05fe744db..955255c36 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -829,7 +829,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
/* Add the user name as an environment variable if it
was given on the command line */
if(conn->bits.user_passwd) {
- snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
+ msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
beg = curl_slist_append(tn->telnet_vars, option_arg);
if(!beg) {
curl_slist_free_all(tn->telnet_vars);
@@ -935,9 +935,9 @@ static void suboption(struct connectdata *conn)
switch(CURL_SB_GET(tn)) {
case CURL_TELOPT_TTYPE:
len = strlen(tn->subopt_ttype) + 4 + 2;
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
- CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+ msnprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+ CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
if(bytes_written < 0) {
err = SOCKERRNO;
@@ -947,9 +947,9 @@ static void suboption(struct connectdata *conn)
break;
case CURL_TELOPT_XDISPLOC:
len = strlen(tn->subopt_xdisploc) + 4 + 2;
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
- CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+ msnprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+ CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
if(bytes_written < 0) {
err = SOCKERRNO;
@@ -958,9 +958,9 @@ static void suboption(struct connectdata *conn)
printsub(data, '>', &temp[2], len-2);
break;
case CURL_TELOPT_NEW_ENVIRON:
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
- CURL_TELQUAL_IS);
+ msnprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+ CURL_TELQUAL_IS);
len = 4;
for(v = tn->telnet_vars; v; v = v->next) {
@@ -968,15 +968,15 @@ static void suboption(struct connectdata *conn)
/* Add the variable only if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
- snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
- CURL_NEW_ENV_VALUE, varval);
+ msnprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+ CURL_NEW_ENV_VALUE, varval);
len += tmplen;
}
}
}
- snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%c", CURL_IAC, CURL_SE);
+ msnprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%c", CURL_IAC, CURL_SE);
len += 2;
bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
if(bytes_written < 0) {
@@ -1692,7 +1692,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
}
#endif
/* mark this as "no further transfer wanted" */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
return result;
}
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index 5b74e8e08..289cda282 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -496,9 +496,9 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
return CURLE_TFTP_ILLEGAL; /* too long file name field */
}
- snprintf((char *)state->spacket.data + 2,
- state->blksize,
- "%s%c%s%c", filename, '\0', mode, '\0');
+ msnprintf((char *)state->spacket.data + 2,
+ state->blksize,
+ "%s%c%s%c", filename, '\0', mode, '\0');
sbytes = 4 + strlen(filename) + strlen(mode);
/* optional addition of TFTP options */
@@ -506,8 +506,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
char buf[64];
/* add tsize option */
if(data->set.upload && (data->state.infilesize != -1))
- snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
- data->state.infilesize);
+ msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
+ data->state.infilesize);
else
strcpy(buf, "0"); /* the destination is large enough */
@@ -517,7 +517,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data + sbytes, buf);
/* add blksize option */
- snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
+ msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data + sbytes,
TFTP_OPTION_BLKSIZE);
@@ -525,7 +525,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
(char *)state->spacket.data + sbytes, buf);
/* add timeout option */
- snprintf(buf, sizeof(buf), "%d", state->retry_time);
+ msnprintf(buf, sizeof(buf), "%d", state->retry_time);
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data + sbytes,
TFTP_OPTION_INTERVAL);
@@ -540,7 +540,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
state->conn->ip_addr->ai_addr,
state->conn->ip_addr->ai_addrlen);
if(senddata != (ssize_t)sbytes) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ char buffer[STRERROR_LEN];
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
}
free(filename);
break;
@@ -590,6 +591,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
ssize_t sbytes;
int rblock;
struct Curl_easy *data = state->conn->data;
+ char buffer[STRERROR_LEN];
switch(event) {
@@ -622,7 +624,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
if(sbytes < 0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
@@ -647,7 +649,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
if(sbytes < 0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
@@ -673,7 +675,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
if(sbytes<0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
}
@@ -713,6 +715,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
size_t cb; /* Bytes currently read */
+ char buffer[STRERROR_LEN];
switch(event) {
@@ -747,7 +750,8 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
state->remote_addrlen);
/* Check all sbytes were sent */
if(sbytes<0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO,
+ buffer, sizeof(buffer)));
result = CURLE_SEND_ERROR;
}
}
@@ -791,7 +795,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
state->remote_addrlen);
/* Check all sbytes were sent */
if(sbytes<0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
/* Update the progress meter */
@@ -817,7 +821,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
state->remote_addrlen);
/* Check all sbytes were sent */
if(sbytes<0) {
- failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_SEND_ERROR;
}
/* since this was a re-send, we remain at the still byte position */
@@ -1005,7 +1009,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
state->sockfd = state->conn->sock[FIRSTSOCKET];
state->state = TFTP_STATE_START;
state->error = TFTP_ERR_NONE;
- state->blksize = TFTP_BLKSIZE_DEFAULT;
+ state->blksize = blksize;
state->requested_blksize = blksize;
((struct sockaddr *)&state->local_addr)->sa_family =
@@ -1030,8 +1034,9 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
conn->ip_addr->ai_addrlen);
if(rc) {
+ char buffer[STRERROR_LEN];
failf(conn->data, "bind() failed; %s",
- Curl_strerror(conn, SOCKERRNO));
+ Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_COULDNT_CONNECT;
}
conn->bits.bound = TRUE;
@@ -1242,7 +1247,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
else {
/* no timeouts to handle, check our socket */
@@ -1251,7 +1256,8 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
if(rc == -1) {
/* bail out */
int error = SOCKERRNO;
- failf(data, "%s", Curl_strerror(conn, error));
+ char buffer[STRERROR_LEN];
+ failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
state->event = TFTP_EVENT_ERROR;
}
else if(rc != 0) {
@@ -1264,7 +1270,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
/* if rc == 0, then select() timed out */
}
diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c
index dce1a761e..e2bd7fd14 100644
--- a/Utilities/cmcurl/lib/timeval.c
+++ b/Utilities/cmcurl/lib/timeval.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -24,26 +24,34 @@
#if defined(WIN32) && !defined(MSDOS)
+/* set in win32_init() */
+extern LARGE_INTEGER Curl_freq;
+extern bool Curl_isVistaOrGreater;
+
struct curltime Curl_now(void)
{
- /*
- ** GetTickCount() is available on _all_ Windows versions from W95 up
- ** to nowadays. Returns milliseconds elapsed since last system boot,
- ** increases monotonically and wraps once 49.7 days have elapsed.
- */
struct curltime now;
-#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
- (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
- (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
- DWORD milliseconds = GetTickCount();
- now.tv_sec = milliseconds / 1000;
- now.tv_usec = (milliseconds % 1000) * 1000;
-#else
- ULONGLONG milliseconds = GetTickCount64();
- now.tv_sec = (time_t) (milliseconds / 1000);
- now.tv_usec = (unsigned int) (milliseconds % 1000) * 1000;
+ if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+ now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
+ now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
+ Curl_freq.QuadPart);
+ }
+ else {
+ /* Disable /analyze warning that GetTickCount64 is preferred */
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:28159)
+#endif
+ DWORD milliseconds = GetTickCount();
+#if defined(_MSC_VER)
+#pragma warning(pop)
#endif
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
+ }
return now;
}
@@ -58,7 +66,9 @@ struct curltime Curl_now(void)
** in any case the time starting point does not change once that the
** system has started up.
*/
+#ifdef HAVE_GETTIMEOFDAY
struct timeval now;
+#endif
struct curltime cnow;
struct timespec tsnow;
@@ -180,7 +190,7 @@ struct curltime Curl_now(void)
*/
timediff_t Curl_timediff(struct curltime newer, struct curltime older)
{
- timediff_t diff = newer.tv_sec-older.tv_sec;
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
if(diff >= (TIME_MAX/1000))
return TIME_MAX;
else if(diff <= (TIME_MIN/1000))
@@ -194,7 +204,7 @@ timediff_t Curl_timediff(struct curltime newer, struct curltime older)
*/
timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
{
- timediff_t diff = newer.tv_sec-older.tv_sec;
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
if(diff >= (TIME_MAX/1000000))
return TIME_MAX;
else if(diff <= (TIME_MIN/1000000))
diff --git a/Utilities/cmcurl/lib/timeval.h b/Utilities/cmcurl/lib/timeval.h
index fb3f680c4..96867d713 100644
--- a/Utilities/cmcurl/lib/timeval.h
+++ b/Utilities/cmcurl/lib/timeval.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -26,8 +26,10 @@
#if SIZEOF_TIME_T < 8
typedef int timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T "d"
#else
typedef curl_off_t timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T
#endif
struct curltime {
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 05ba862c2..514330e8c 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -117,6 +117,35 @@ CURLcode Curl_get_upload_buffer(struct Curl_easy *data)
return CURLE_OK;
}
+#ifndef CURL_DISABLE_HTTP
+/*
+ * 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)
+{
+ struct Curl_easy *data = (struct Curl_easy *)raw;
+ Curl_send_buffer *trailers_buf = data->state.trailers_buf;
+ size_t bytes_left = trailers_buf->size_used-data->state.trailers_bytes_sent;
+ size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left;
+ if(to_copy) {
+ memcpy(buffer,
+ &trailers_buf->buffer[data->state.trailers_bytes_sent],
+ to_copy);
+ data->state.trailers_bytes_sent += to_copy;
+ }
+ return to_copy;
+}
+
+static size_t Curl_trailers_left(void *raw)
+{
+ struct Curl_easy *data = (struct Curl_easy *)raw;
+ Curl_send_buffer *trailers_buf = data->state.trailers_buf;
+ return trailers_buf->size_used - data->state.trailers_bytes_sent;
+}
+#endif
+
/*
* This function will call the read callback to fill our buffer with data
* to upload.
@@ -127,6 +156,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
struct Curl_easy *data = conn->data;
size_t buffersize = bytes;
size_t nread;
+
+ curl_read_callback readfunc = NULL;
+ void *extra_data = NULL;
+
#ifdef CURL_DOES_CONVERSIONS
bool sending_http_headers = FALSE;
@@ -140,15 +173,75 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
}
#endif
- if(data->req.upload_chunky) {
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_INITIALIZED) {
+ struct curl_slist *trailers = NULL;
+ CURLcode c;
+ int trailers_ret_code;
+
+ /* at this point we already verified that the callback exists
+ so we compile and store the trailers buffer, then proceed */
+ infof(data,
+ "Moving trailers state machine from initialized to sending.\n");
+ data->state.trailers_state = TRAILERS_SENDING;
+ data->state.trailers_buf = Curl_add_buffer_init();
+ if(!data->state.trailers_buf) {
+ failf(data, "Unable to allocate trailing headers buffer !");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->state.trailers_bytes_sent = 0;
+ Curl_set_in_callback(data, true);
+ trailers_ret_code = data->set.trailer_callback(&trailers,
+ data->set.trailer_data);
+ Curl_set_in_callback(data, false);
+ if(trailers_ret_code == CURL_TRAILERFUNC_OK) {
+ c = Curl_http_compile_trailers(trailers, data->state.trailers_buf, data);
+ }
+ else {
+ failf(data, "operation aborted by trailing headers callback");
+ *nreadp = 0;
+ c = CURLE_ABORTED_BY_CALLBACK;
+ }
+ if(c != CURLE_OK) {
+ Curl_add_buffer_free(&data->state.trailers_buf);
+ curl_slist_free_all(trailers);
+ return c;
+ }
+ infof(data, "Successfully compiled trailers.\r\n");
+ curl_slist_free_all(trailers);
+ }
+#endif
+
+ /* if we are transmitting trailing data, we don't need to write
+ a chunk size so we skip this */
+ if(data->req.upload_chunky &&
+ data->state.trailers_state == TRAILERS_NONE) {
/* if chunked Transfer-Encoding */
buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
}
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_SENDING) {
+ /* if we're here then that means that we already sent the last empty chunk
+ but we didn't send a final CR LF, so we sent 0 CR LF. We then start
+ pulling trailing data until we ²have no more at which point we
+ simply return to the previous point in the state machine as if
+ nothing happened.
+ */
+ readfunc = Curl_trailers_read;
+ extra_data = (void *)data;
+ }
+ else
+#endif
+ {
+ readfunc = data->state.fread_func;
+ extra_data = data->state.in;
+ }
+
Curl_set_in_callback(data, true);
- nread = data->state.fread_func(data->req.upload_fromhere, 1,
- buffersize, data->state.in);
+ nread = readfunc(data->req.upload_fromhere, 1,
+ buffersize, extra_data);
Curl_set_in_callback(data, false);
if(nread == CURL_READFUNC_ABORT) {
@@ -200,10 +293,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
here, knowing they'll become CRLFs later on.
*/
- char hexbuffer[11];
+ bool added_crlf = FALSE;
+ int hexlen = 0;
const char *endofline_native;
const char *endofline_network;
- int hexlen;
if(
#ifdef CURL_DO_LINEEND_CONV
@@ -218,20 +311,37 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
endofline_native = "\r\n";
endofline_network = "\x0d\x0a";
}
- hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
- "%x%s", nread, endofline_native);
- /* move buffer pointer */
- data->req.upload_fromhere -= hexlen;
- nread += hexlen;
+ /* if we're not handling trailing data, proceed as usual */
+ if(data->state.trailers_state != TRAILERS_SENDING) {
+ char hexbuffer[11] = "";
+ hexlen = msnprintf(hexbuffer, sizeof(hexbuffer),
+ "%zx%s", nread, endofline_native);
- /* copy the prefix to the buffer, leaving out the NUL */
- memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+ /* move buffer pointer */
+ data->req.upload_fromhere -= hexlen;
+ nread += hexlen;
- /* always append ASCII CRLF to the data */
- memcpy(data->req.upload_fromhere + nread,
- endofline_network,
- strlen(endofline_network));
+ /* copy the prefix to the buffer, leaving out the NUL */
+ memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+ /* always append ASCII CRLF to the data unless
+ we have a valid trailer callback */
+#ifndef CURL_DISABLE_HTTP
+ if((nread-hexlen) == 0 &&
+ data->set.trailer_callback != NULL &&
+ data->state.trailers_state == TRAILERS_NONE) {
+ data->state.trailers_state = TRAILERS_INITIALIZED;
+ }
+ else
+#endif
+ {
+ memcpy(data->req.upload_fromhere + nread,
+ endofline_network,
+ strlen(endofline_network));
+ added_crlf = TRUE;
+ }
+ }
#ifdef CURL_DOES_CONVERSIONS
{
@@ -242,22 +352,40 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
length = nread;
else
/* just translate the protocol portion */
- length = strlen(hexbuffer);
- result = Curl_convert_to_network(data, data->req.upload_fromhere,
- length);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(result)
- return result;
+ length = hexlen;
+ if(length) {
+ result = Curl_convert_to_network(data, data->req.upload_fromhere,
+ length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
+ }
}
#endif /* CURL_DOES_CONVERSIONS */
- if((nread - hexlen) == 0) {
- /* mark this as done once this chunk is transferred */
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_SENDING &&
+ !Curl_trailers_left(data)) {
+ Curl_add_buffer_free(&data->state.trailers_buf);
+ data->state.trailers_state = TRAILERS_DONE;
+ data->set.trailer_data = NULL;
+ data->set.trailer_callback = NULL;
+ /* mark the transfer as done */
data->req.upload_done = TRUE;
- infof(data, "Signaling end of chunked upload via terminating chunk.\n");
+ infof(data, "Signaling end of chunked upload after trailers.\n");
}
+ else
+#endif
+ if((nread - hexlen) == 0 &&
+ data->state.trailers_state != TRAILERS_INITIALIZED) {
+ /* mark this as done once this chunk is transferred */
+ data->req.upload_done = TRUE;
+ infof(data,
+ "Signaling end of chunked upload via terminating chunk.\n");
+ }
- nread += strlen(endofline_native); /* for the added end of line */
+ if(added_crlf)
+ nread += strlen(endofline_network); /* for the added end of line */
}
#ifdef CURL_DOES_CONVERSIONS
else if((data->set.prefer_ascii) && (!sending_http_headers)) {
@@ -333,7 +461,6 @@ CURLcode Curl_readrewind(struct connectdata *conn)
infof(data, "the ioctl callback returned %d\n", (int)err);
if(err) {
- /* FIXME: convert to a human readable error message */
failf(data, "ioctl callback returned error %d", (int)err);
return CURLE_SEND_FAIL_REWIND;
}
@@ -376,35 +503,6 @@ static int data_pending(const struct connectdata *conn)
#endif
}
-static void read_rewind(struct connectdata *conn,
- size_t thismuch)
-{
- DEBUGASSERT(conn->read_pos >= thismuch);
-
- conn->read_pos -= thismuch;
- conn->bits.stream_was_rewound = TRUE;
-
-#ifdef DEBUGBUILD
- {
- char buf[512 + 1];
- size_t show;
-
- show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
- if(conn->master_buffer) {
- memcpy(buf, conn->master_buffer + conn->read_pos, show);
- buf[show] = '\0';
- }
- else {
- buf[0] = '\0';
- }
-
- DEBUGF(infof(conn->data,
- "Buffer after stream rewind (read_pos = %zu): [%s]\n",
- conn->read_pos, buf));
- }
-#endif
-}
-
/*
* Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
* remote document with the time provided by CURLOPT_TIMEVAL
@@ -479,9 +577,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
conn->httpversion == 20) &&
#endif
k->size != -1 && !k->header) {
- /* make sure we don't read "too much" if we can help it since we
- might be pipelining and then someone else might want to read what
- follows! */
+ /* make sure we don't read too much */
curl_off_t totalleft = k->size - k->bytecount;
if(totalleft < (curl_off_t)bytestoread)
bytestoread = (size_t)totalleft;
@@ -520,7 +616,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(0 < nread || is_empty_data) {
k->buf[nread] = 0;
}
- else if(0 >= nread) {
+ else {
/* if we receive 0 or less here, the server closed the connection
and we bail out from this! */
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
@@ -563,20 +659,11 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* We've stopped dealing with input, get out of the do-while loop */
if(nread > 0) {
- if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
- infof(data,
- "Rewinding stream by : %zd"
- " bytes on url %s (zero-length body)\n",
- nread, data->state.up.path);
- read_rewind(conn, (size_t)nread);
- }
- else {
- infof(data,
- "Excess found in a non pipelined read:"
- " excess = %zd"
- " url = %s (zero-length body)\n",
- nread, data->state.up.path);
- }
+ infof(data,
+ "Excess found:"
+ " excess = %zd"
+ " url = %s (zero-length body)\n",
+ nread, data->state.up.path);
}
break;
@@ -707,19 +794,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* There are now possibly N number of bytes at the end of the
str buffer that weren't written to the client.
-
- We DO care about this data if we are pipelining.
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);
- if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
- /* only attempt the rewind if we truly are pipelining */
- infof(conn->data, "Rewinding %zu bytes\n",dataleft);
- read_rewind(conn, dataleft);
- }
}
}
/* If it returned OK, we just keep going */
@@ -738,25 +818,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
excess = (size_t)(k->bytecount + nread - k->maxdownload);
if(excess > 0 && !k->ignorebody) {
- if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
- infof(data,
- "Rewinding stream by : %zu"
- " bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T
- ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
- ", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n",
- excess, data->state.up.path,
- k->size, k->maxdownload, k->bytecount, nread);
- read_rewind(conn, excess);
- }
- else {
- infof(data,
- "Excess found in a non pipelined read:"
- " excess = %zu"
- ", size = %" CURL_FORMAT_CURL_OFF_T
- ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
- ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
- excess, k->size, k->maxdownload, k->bytecount);
- }
+ infof(data,
+ "Excess found in a read:"
+ " excess = %zu"
+ ", size = %" CURL_FORMAT_CURL_OFF_T
+ ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
+ excess, k->size, k->maxdownload, k->bytecount);
}
nread = (ssize_t) (k->maxdownload - k->bytecount);
@@ -844,6 +912,11 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->keepon &= ~KEEP_RECV;
}
+ if(k->keepon & KEEP_RECV_PAUSE) {
+ /* this is a paused transfer */
+ break;
+ }
+
} while(data_pending(conn) && maxloops--);
if(maxloops <= 0) {
@@ -920,7 +993,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
*didwhat |= KEEP_SEND;
do {
-
/* only read more data if there's no upload data already
present in the upload buffer */
if(0 == k->upload_present) {
@@ -945,7 +1017,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
k->keepon &= ~KEEP_SEND; /* disable writing */
k->start100 = Curl_now(); /* timeout count starts now */
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
-
/* set a timeout for the multi interface */
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
break;
@@ -1065,6 +1136,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
(size_t)bytes_written);
k->writebytecount += bytes_written;
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
if((!k->upload_chunky || k->forbidchunk) &&
(k->writebytecount == data->state.infilesize)) {
@@ -1098,7 +1170,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
}
}
- Curl_pgrsSetUploadCounter(data, k->writebytecount);
} WHILE_FALSE; /* just to break out from! */
@@ -1176,11 +1247,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
k->now = Curl_now();
if(didwhat) {
- /* Update read/write counters */
- if(k->bytecountp)
- *k->bytecountp = k->bytecount; /* read count */
- if(k->writebytecountp)
- *k->writebytecountp = k->writebytecount; /* write count */
+ ;
}
else {
/* no read no write, this is a timeout? */
@@ -1219,15 +1286,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(k->keepon) {
if(0 > Curl_timeleft(data, &k->now, FALSE)) {
if(k->size != -1) {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " out of %"
+ 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(k->now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(k->now, data->progress.t_startsingle),
k->bytecount);
}
@@ -1348,17 +1415,30 @@ void Curl_init_CONNECT(struct Curl_easy *data)
CURLcode Curl_pretransfer(struct Curl_easy *data)
{
CURLcode result;
- if(!data->change.url) {
+
+ if(!data->change.url && !data->set.uh) {
/* we can't do anything without URL */
failf(data, "No URL set!");
return CURLE_URL_MALFORMAT;
}
+
/* since the URL may have been redirected in a previous use of this handle */
if(data->change.url_alloc) {
/* the already set URL is allocated, free it first! */
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
+
+ if(!data->change.url && data->set.uh) {
+ CURLUcode uc;
+ uc = curl_url_get(data->set.uh,
+ CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
+ if(uc) {
+ failf(data, "No URL set!");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
data->change.url = data->set.str[STRING_SET_URL];
/* Init the SSL session ID cache here. We do it here since we want to do it
@@ -1382,11 +1462,14 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(data->set.httpreq == HTTPREQ_PUT)
data->state.infilesize = data->set.filesize;
- else {
+ else if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD)) {
data->state.infilesize = data->set.postfieldsize;
if(data->set.postfields && (data->state.infilesize == -1))
data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
}
+ else
+ data->state.infilesize = 0;
/* If there is a list of cookie files to read, do it now! */
if(data->change.cookielist)
@@ -1414,18 +1497,13 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
Curl_pgrsResetTransferSizes(data);
Curl_pgrsStartNow(data);
- if(data->set.timeout)
- Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
-
- if(data->set.connecttimeout)
- Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
-
/* In case the handle is re-used and an authentication method was picked
in the session we need to make sure we only use the one(s) we now
consider to be fine */
data->state.authhost.picked &= data->state.authhost.want;
data->state.authproxy.picked &= data->state.authproxy.want;
+#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch) {
struct WildcardData *wc = &data->wildcard;
if(wc->state < CURLWC_INIT) {
@@ -1434,6 +1512,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
}
+#endif
}
return result;
@@ -1516,12 +1595,22 @@ CURLcode Curl_follow(struct Curl_easy *data,
DEBUGASSERT(data->state.uh);
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
(type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : 0);
- if(uc)
- return Curl_uc_to_curlcode(uc);
+ if(uc) {
+ if(type != FOLLOW_FAKE)
+ return Curl_uc_to_curlcode(uc);
+
+ /* the URL could not be parsed for some reason, but since this is FAKE
+ mode, just duplicate the field as-is */
+ newurl = strdup(newurl);
+ if(!newurl)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
- uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
- if(uc)
- return Curl_uc_to_curlcode(uc);
+ uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
+ }
if(type == FOLLOW_FAKE) {
/* we're only figuring out the new url if we would've followed locations
@@ -1704,8 +1793,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
- struct HTTP *http = data->req.protop;
- if(http->writebytecount) {
+ if(data->req.writebytecount) {
CURLcode result = Curl_readrewind(conn);
if(result) {
Curl_safefree(*url);
@@ -1723,24 +1811,17 @@ CURLcode Curl_retry_request(struct connectdata *conn,
*/
void
Curl_setup_transfer(
- struct connectdata *conn, /* connection data */
+ struct Curl_easy *data, /* transfer */
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
- curl_off_t *bytecountp, /* return number of bytes read or NULL */
- int writesockindex, /* socket index to write to, it may very well be
+ int writesockindex /* socket index to write to, it may very well be
the same we read from. -1 disables */
- curl_off_t *writecountp /* return number of bytes written or NULL */
)
{
- struct Curl_easy *data;
- struct SingleRequest *k;
-
+ struct SingleRequest *k = &data->req;
+ struct connectdata *conn = data->conn;
DEBUGASSERT(conn != NULL);
-
- data = conn->data;
- k = &data->req;
-
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
if(conn->bits.multiplex || conn->httpversion == 20) {
@@ -1759,8 +1840,6 @@ Curl_setup_transfer(
k->getheader = getheader;
k->size = size;
- k->bytecountp = bytecountp;
- k->writebytecountp = writecountp;
/* The code sequence below is placed in this function just because all
necessary input is not always known in do_complete() as this function may
diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h
index 9742455ae..a9bff6348 100644
--- a/Utilities/cmcurl/lib/transfer.h
+++ b/Utilities/cmcurl/lib/transfer.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -59,15 +59,13 @@ CURLcode Curl_get_upload_buffer(struct Curl_easy *data);
/* This sets up a forthcoming transfer */
void
-Curl_setup_transfer (struct connectdata *data,
- int sockindex, /* socket index to read from or -1 */
- curl_off_t size, /* -1 if unknown at this point */
- bool getheader, /* TRUE if header parsing is wanted */
- curl_off_t *bytecountp, /* return number of bytes read */
- int writesockindex, /* socket index to write to, it may
- very well be the same we read from.
- -1 disables */
- curl_off_t *writecountp /* return number of bytes written */
-);
+Curl_setup_transfer (struct Curl_easy *data,
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ int writesockindex /* socket index to write to. May be
+ the same we read from. -1
+ disables */
+ );
#endif /* HEADER_CURL_TRANSFER_H */
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 0d5a13f99..c441ae716 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -109,17 +109,16 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "connect.h"
#include "inet_ntop.h"
#include "http_ntlm.h"
-#include "curl_ntlm_wb.h"
#include "socks.h"
#include "curl_rtmp.h"
#include "gopher.h"
#include "http_proxy.h"
#include "conncache.h"
#include "multihandle.h"
-#include "pipeline.h"
#include "dotdot.h"
#include "strdup.h"
#include "setopt.h"
+#include "altsvc.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -127,7 +126,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h"
static void conn_free(struct connectdata *conn);
-static void free_fixed_hostname(struct hostname *host);
+static void free_idnconverted_hostname(struct hostname *host);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -186,11 +185,11 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_tftp,
#endif
-#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
+#if defined(USE_SSH)
&Curl_handler_scp,
#endif
-#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
+#if defined(USE_SSH)
&Curl_handler_sftp,
#endif
@@ -292,7 +291,7 @@ void Curl_freeset(struct Curl_easy *data)
}
/* free the URL pieces */
-void Curl_up_free(struct Curl_easy *data)
+static void up_free(struct Curl_easy *data)
{
struct urlpieces *up = &data->state.up;
Curl_safefree(up->scheme);
@@ -369,12 +368,19 @@ CURLcode Curl_close(struct Curl_easy *data)
}
data->change.referer = NULL;
- Curl_up_free(data);
+ up_free(data);
Curl_safefree(data->state.buffer);
Curl_safefree(data->state.headerbuff);
Curl_safefree(data->state.ulbuf);
Curl_flush_cookies(data, 1);
- Curl_digest_cleanup(data);
+#ifdef USE_ALTSVC
+ Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]);
+ Curl_altsvc_cleanup(data->asi);
+ data->asi = NULL;
+#endif
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+ Curl_http_auth_cleanup_digest(data);
+#endif
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
@@ -433,11 +439,12 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->httpreq = HTTPREQ_GET; /* Default HTTP request */
set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
+#ifndef CURL_DISABLE_FILE
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
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;
-
+#endif
set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
/* Set the default size of the SSL session ID cache */
@@ -492,9 +499,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
/* Set the default CA cert bundle/path detected/specified at build time.
*
- * If Schannel (WinSSL) is the selected SSL backend then these locations
- * are ignored. We allow setting CA location for schannel only when
- * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+ * If Schannel is the selected SSL backend then these locations are
+ * ignored. We allow setting CA location for schannel only when explicitly
+ * specified by the user via CURLOPT_CAINFO / --cacert.
*/
if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
#if defined(CURL_CA_BUNDLE)
@@ -536,6 +543,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->fnmatch = ZERO_NULL;
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+ set->maxage_conn = 118;
+ set->http09_allowed = TRUE;
set->httpversion =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
@@ -570,7 +579,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
- result = Curl_resolver_init(&data->state.resolver);
+ result = Curl_resolver_init(data, &data->state.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
free(data);
@@ -659,11 +668,15 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
-static void conn_free(struct connectdata *conn)
+
+static void conn_shutdown(struct connectdata *conn)
{
if(!conn)
return;
+ infof(conn->data, "Closing connection %ld\n", conn->connection_id);
+ DEBUGASSERT(conn->data);
+
/* possible left-overs from the async name resolvers */
Curl_resolver_cancel(conn);
@@ -682,10 +695,20 @@ static void conn_free(struct connectdata *conn)
if(CURL_SOCKET_BAD != conn->tempsock[1])
Curl_closesocket(conn, conn->tempsock[1]);
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
- Curl_ntlm_wb_cleanup(conn);
-#endif
+ /* unlink ourselves. this should be called last since other shutdown
+ procedures need a valid conn->data and this may clear it. */
+ Curl_conncache_remove_conn(conn->data, conn, TRUE);
+}
+
+static void conn_free(struct connectdata *conn)
+{
+ if(!conn)
+ return;
+
+ free_idnconverted_hostname(&conn->host);
+ free_idnconverted_hostname(&conn->conn_to_host);
+ free_idnconverted_hostname(&conn->http_proxy.host);
+ free_idnconverted_hostname(&conn->socks_proxy.host);
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
@@ -708,17 +731,14 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
- Curl_safefree(conn->master_buffer);
Curl_safefree(conn->connect_state);
conn_reset_all_postponed_data(conn);
-
- Curl_llist_destroy(&conn->send_pipe, NULL);
- Curl_llist_destroy(&conn->recv_pipe, NULL);
-
+ Curl_llist_destroy(&conn->easyq, NULL);
Curl_safefree(conn->localdev);
Curl_free_primary_ssl_config(&conn->ssl_config);
Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
@@ -767,7 +787,6 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
- conn->data = data;
if(conn->dns_entry != NULL) {
Curl_resolv_unlock(data, conn->dns_entry);
conn->dns_entry = NULL;
@@ -777,27 +796,26 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
/* Cleanup NTLM connection-related data */
- Curl_http_ntlm_cleanup(conn);
+ Curl_http_auth_cleanup_ntlm(conn);
#endif
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+ /* Cleanup NEGOTIATE connection-related data */
+ Curl_http_auth_cleanup_negotiate(conn);
+#endif
+
+ /* 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;
if(conn->handler->disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->handler->disconnect(conn, dead_connection);
- /* unlink ourselves! */
- infof(data, "Closing connection %ld\n", conn->connection_id);
- Curl_conncache_remove_conn(conn, TRUE);
-
- free_fixed_hostname(&conn->host);
- free_fixed_hostname(&conn->conn_to_host);
- free_fixed_hostname(&conn->http_proxy.host);
- free_fixed_hostname(&conn->socks_proxy.host);
-
- DEBUGASSERT(conn->data == data);
- /* this assumes that the pointer is still there after the connection was
- detected from the cache */
- Curl_ssl_close(conn, FIRSTSOCKET);
-
+ conn_shutdown(conn);
conn_free(conn);
return CURLE_OK;
}
@@ -821,28 +839,21 @@ static bool SocketIsDead(curl_socket_t sock)
}
/*
- * IsPipeliningPossible()
+ * IsMultiplexingPossible()
*
- * Return a bitmask with the available pipelining and multiplexing options for
- * the given requested connection.
+ * Return a bitmask with the available multiplexing options for the given
+ * requested connection.
*/
-static int IsPipeliningPossible(const struct Curl_easy *handle,
- const struct connectdata *conn)
+static int IsMultiplexingPossible(const struct Curl_easy *handle,
+ const struct connectdata *conn)
{
int avail = 0;
- /* If a HTTP protocol and pipelining is enabled */
+ /* If a HTTP protocol and multiplexing is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(!conn->bits.protoconnstart || !conn->bits.close)) {
- if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
- (handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
- (handle->set.httpreq == HTTPREQ_GET ||
- handle->set.httpreq == HTTPREQ_HEAD))
- /* didn't ask for HTTP/1.0 and a GET or HEAD */
- avail |= CURLPIPE_HTTP1;
-
- if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) &&
+ if(Curl_multiplex_wanted(handle->multi) &&
(handle->set.httpversion >= CURL_HTTP_VERSION_2))
/* allows HTTP/2 */
avail |= CURLPIPE_MULTIPLEX;
@@ -850,84 +861,7 @@ static int IsPipeliningPossible(const struct Curl_easy *handle,
return avail;
}
-/* Returns non-zero if a handle was removed */
-int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
- struct curl_llist *pipeline)
-{
- if(pipeline) {
- struct curl_llist_element *curr;
-
- curr = pipeline->head;
- while(curr) {
- if(curr->ptr == handle) {
- Curl_llist_remove(pipeline, curr, NULL);
- return 1; /* we removed a handle */
- }
- curr = curr->next;
- }
- }
-
- return 0;
-}
-
-#if 0 /* this code is saved here as it is useful for debugging purposes */
-static void Curl_printPipeline(struct curl_llist *pipeline)
-{
- struct curl_llist_element *curr;
-
- curr = pipeline->head;
- while(curr) {
- struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
- infof(data, "Handle in pipeline: %s\n", data->state.path);
- curr = curr->next;
- }
-}
-#endif
-
-static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
-{
- struct curl_llist_element *curr = pipeline->head;
-#ifdef DEBUGBUILD
- {
- struct curl_llist_element *p = pipeline->head;
- while(p) {
- struct Curl_easy *e = p->ptr;
- DEBUGASSERT(GOOD_EASY_HANDLE(e));
- p = p->next;
- }
- }
-#endif
- if(curr) {
- return (struct Curl_easy *) curr->ptr;
- }
-
- return NULL;
-}
-
-/* remove the specified connection from all (possible) pipelines and related
- queues */
-void Curl_getoff_all_pipelines(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(!conn->bundle)
- return;
- if(conn->bundle->multiuse == BUNDLE_PIPELINING) {
- bool recv_head = (conn->readchannel_inuse &&
- Curl_recvpipe_head(data, conn));
- bool send_head = (conn->writechannel_inuse &&
- Curl_sendpipe_head(data, conn));
-
- if(Curl_removeHandleFromPipeline(data, &conn->recv_pipe) && recv_head)
- Curl_pipeline_leave_read(conn);
- if(Curl_removeHandleFromPipeline(data, &conn->send_pipe) && send_head)
- Curl_pipeline_leave_write(conn);
- }
- else {
- (void)Curl_removeHandleFromPipeline(data, &conn->recv_pipe);
- (void)Curl_removeHandleFromPipeline(data, &conn->send_pipe);
- }
-}
-
+#ifndef CURL_DISABLE_PROXY
static bool
proxy_info_matches(const struct proxy_info* data,
const struct proxy_info* needle)
@@ -939,6 +873,10 @@ proxy_info_matches(const struct proxy_info* data,
return FALSE;
}
+#else
+/* disabled, won't get called */
+#define proxy_info_matches(x,y) FALSE
+#endif
/*
* This function checks if the given connection is dead and extracts it from
@@ -952,20 +890,18 @@ proxy_info_matches(const struct proxy_info* data,
static bool extract_if_dead(struct connectdata *conn,
struct Curl_easy *data)
{
- size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size;
- if(!pipeLen && !CONN_INUSE(conn)) {
- /* The check for a dead socket makes sense only if there are no
- handles in pipeline and the connection isn't already marked in
+ if(!CONN_INUSE(conn) && !conn->data) {
+ /* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
-
- conn->data = data;
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;
dead = (state & CONNRESULT_DEAD);
}
else {
@@ -975,8 +911,7 @@ static bool extract_if_dead(struct connectdata *conn,
if(dead) {
infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
- Curl_conncache_remove_conn(conn, FALSE);
- conn->data = NULL; /* detach */
+ Curl_conncache_remove_conn(data, conn, FALSE);
return TRUE;
}
}
@@ -1026,13 +961,25 @@ static void prune_dead_connections(struct Curl_easy *data)
}
}
+/* A connection has to have been idle for a shorter time than 'maxage_conn' to
+ be subject for reuse. The success rate is just too low after this. */
-static size_t max_pipeline_length(struct Curl_multi *multi)
+static bool conn_maxage(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct curltime now)
{
- return multi ? multi->max_pipeline_length : 0;
-}
-
+ if(!conn->data) {
+ timediff_t idletime = Curl_timediff(now, conn->lastused);
+ idletime /= 1000; /* integer seconds is fine */
+ if(idletime/1000 > data->set.maxage_conn) {
+ infof(data, "Too old connection (%ld seconds), disconnect it\n",
+ idletime);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
/*
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details
@@ -1042,8 +989,7 @@ static size_t max_pipeline_length(struct Curl_multi *multi)
* connection as 'in-use'. It must later be called with ConnectionDone() to
* return back to 'idle' (unused) state.
*
- * The force_reuse flag is set if the connection must be used, even if
- * the pipelining strategy wants to open a new connection instead of reusing.
+ * The force_reuse flag is set if the connection must be used.
*/
static bool
ConnectionExists(struct Curl_easy *data,
@@ -1055,8 +1001,9 @@ ConnectionExists(struct Curl_easy *data,
struct connectdata *check;
struct connectdata *chosen = 0;
bool foundPendingCandidate = FALSE;
- int canpipe = IsPipeliningPossible(data, needle);
+ bool canmultiplex = IsMultiplexingPossible(data, needle);
struct connectbundle *bundle;
+ struct curltime now = Curl_now();
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want &
@@ -1071,59 +1018,47 @@ ConnectionExists(struct Curl_easy *data,
*force_reuse = FALSE;
*waitpipe = FALSE;
- /* We can't pipeline if the site is blacklisted */
- if((canpipe & CURLPIPE_HTTP1) &&
- Curl_pipeline_site_blacklisted(data, needle))
- canpipe &= ~ CURLPIPE_HTTP1;
-
/* 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);
if(bundle) {
/* Max pipe length is zero (unlimited) for multiplexed connections */
- size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)?
- max_pipeline_length(data->multi):0;
- size_t best_pipe_len = max_pipe_len;
struct curl_llist_element *curr;
infof(data, "Found bundle for host %s: %p [%s]\n",
(needle->bits.conn_to_host ? needle->conn_to_host.name :
needle->host.name), (void *)bundle,
- (bundle->multiuse == BUNDLE_PIPELINING ?
- "can pipeline" :
- (bundle->multiuse == BUNDLE_MULTIPLEX ?
- "can multiplex" : "serially")));
-
- /* We can't pipeline if we don't know anything about the server */
- if(canpipe) {
- if(bundle->multiuse <= BUNDLE_UNKNOWN) {
+ (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially"));
+
+ /* We can't multiplex if we don't know anything about the server */
+ if(canmultiplex) {
+ if(bundle->multiuse == BUNDLE_UNKNOWN) {
if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
- infof(data, "Server doesn't support multi-use yet, wait\n");
+ infof(data, "Server doesn't support multiplex yet, wait\n");
*waitpipe = TRUE;
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
return FALSE; /* no re-use */
}
- infof(data, "Server doesn't support multi-use (yet)\n");
- canpipe = 0;
+ infof(data, "Server doesn't support multiplex (yet)\n");
+ canmultiplex = FALSE;
}
- if((bundle->multiuse == BUNDLE_PIPELINING) &&
- !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) {
- /* not asked for, switch off */
- infof(data, "Could pipeline, but not asked to!\n");
- canpipe = 0;
- }
- else if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
- !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) {
+ if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
+ !Curl_multiplex_wanted(data->multi)) {
infof(data, "Could multiplex, but not asked to!\n");
- canpipe = 0;
+ canmultiplex = FALSE;
+ }
+ if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
+ infof(data, "Can not multiplex, even if we wanted to!\n");
+ canmultiplex = FALSE;
}
}
curr = bundle->conn_list.head;
while(curr) {
bool match = FALSE;
- size_t pipeLen;
+ size_t multiplexed;
/*
* Note that if we use a HTTP proxy in normal mode (no tunneling), we
@@ -1132,35 +1067,25 @@ ConnectionExists(struct Curl_easy *data,
check = curr->ptr;
curr = curr->next;
- if(extract_if_dead(check, data)) {
+ if(check->bits.connect_only)
+ /* connect-only connections will not be reused */
+ continue;
+
+ if(conn_maxage(data, check, now) || extract_if_dead(check, data)) {
/* disconnect it */
(void)Curl_disconnect(data, check, /* dead_connection */TRUE);
continue;
}
- pipeLen = check->send_pipe.size + check->recv_pipe.size;
+ multiplexed = CONN_INUSE(check) &&
+ (bundle->multiuse == BUNDLE_MULTIPLEX);
- if(canpipe) {
+ if(canmultiplex) {
if(check->bits.protoconnstart && check->bits.close)
continue;
-
- if(!check->bits.multiplex) {
- /* If not multiplexing, make sure the connection is fine for HTTP/1
- pipelining */
- struct Curl_easy* sh = gethandleathead(&check->send_pipe);
- struct Curl_easy* rh = gethandleathead(&check->recv_pipe);
- if(sh) {
- if(!(IsPipeliningPossible(sh, check) & CURLPIPE_HTTP1))
- continue;
- }
- else if(rh) {
- if(!(IsPipeliningPossible(rh, check) & CURLPIPE_HTTP1))
- continue;
- }
- }
}
else {
- if(pipeLen > 0) {
+ if(multiplexed) {
/* can only happen within multi handles, and means that another easy
handle is using this connection */
continue;
@@ -1185,13 +1110,6 @@ ConnectionExists(struct Curl_easy *data,
to get closed. */
infof(data, "Connection #%ld isn't open enough, can't reuse\n",
check->connection_id);
-#ifdef DEBUGBUILD
- if(check->recv_pipe.size > 0) {
- infof(data,
- "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
- check->connection_id);
- }
-#endif
continue;
}
}
@@ -1262,14 +1180,15 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if(!canpipe && CONN_INUSE(check))
- /* this request can't be pipelined but the checked connection is
+ if(!canmultiplex && check->data)
+ /* this request can't be multiplexed but the checked connection is
already in use so we skip it */
continue;
- if(CONN_INUSE(check) && (check->data->multi != needle->data->multi))
- /* this could be subject for pipeline/multiplex use, but only
- if they belong to the same multi handle */
+ if(CONN_INUSE(check) && check->data &&
+ (check->data->multi != needle->data->multi))
+ /* this could be subject for multiplex use, but only if they belong to
+ * the same multi handle */
continue;
if(needle->localdev || needle->localport) {
@@ -1360,7 +1279,7 @@ ConnectionExists(struct Curl_easy *data,
strcmp(needle->passwd, check->passwd))
continue;
}
- else if(check->ntlm.state != NTLMSTATE_NONE) {
+ else if(check->http_ntlm_state != NTLMSTATE_NONE) {
/* Connection is using NTLM auth but we don't want NTLM */
continue;
}
@@ -1376,7 +1295,7 @@ ConnectionExists(struct Curl_easy *data,
strcmp(needle->http_proxy.passwd, check->http_proxy.passwd))
continue;
}
- else if(check->proxyntlm.state != NTLMSTATE_NONE) {
+ else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
/* Proxy connection is using NTLM auth but we don't want NTLM */
continue;
}
@@ -1386,9 +1305,9 @@ ConnectionExists(struct Curl_easy *data,
chosen = check;
if((wantNTLMhttp &&
- (check->ntlm.state != NTLMSTATE_NONE)) ||
+ (check->http_ntlm_state != NTLMSTATE_NONE)) ||
(wantProxyNTLMhttp &&
- (check->proxyntlm.state != NTLMSTATE_NONE))) {
+ (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
/* We must use this connection, no other */
*force_reuse = TRUE;
break;
@@ -1398,55 +1317,32 @@ ConnectionExists(struct Curl_easy *data,
continue;
}
#endif
- if(canpipe) {
- /* We can pipeline if we want to. Let's continue looking for
- the optimal connection to use, i.e the shortest pipe that is not
- blacklisted. */
+ if(canmultiplex) {
+ /* We can multiplex if we want to. Let's continue looking for
+ the optimal connection to use. */
- if(pipeLen == 0) {
+ if(!multiplexed) {
/* We have the optimal connection. Let's stop looking. */
chosen = check;
break;
}
- /* We can't use the connection if the pipe is full */
- if(max_pipe_len && (pipeLen >= max_pipe_len)) {
- infof(data, "Pipe is full, skip (%zu)\n", pipeLen);
- continue;
- }
#ifdef USE_NGHTTP2
/* If multiplexed, make sure we don't go over concurrency limit */
if(check->bits.multiplex) {
/* Multiplexed connections can only be HTTP/2 for now */
struct http_conn *httpc = &check->proto.httpc;
- if(pipeLen >= httpc->settings.max_concurrent_streams) {
+ if(multiplexed >= httpc->settings.max_concurrent_streams) {
infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n",
- pipeLen);
+ multiplexed);
continue;
}
}
#endif
- /* We can't use the connection if the pipe is penalized */
- if(Curl_pipeline_penalized(data, check)) {
- infof(data, "Penalized, skip\n");
- continue;
- }
-
- if(max_pipe_len) {
- if(pipeLen < best_pipe_len) {
- /* This connection has a shorter pipe so far. We'll pick this
- and continue searching */
- chosen = check;
- best_pipe_len = pipeLen;
- continue;
- }
- }
- else {
- /* When not pipelining (== multiplexed), we have a match here! */
- chosen = check;
- infof(data, "Multiplexed connection found!\n");
- break;
- }
+ /* When not multiplexed, we have a match here! */
+ chosen = check;
+ infof(data, "Multiplexed connection found!\n");
+ break;
}
else {
/* We have found a connection. Let's stop searching. */
@@ -1460,11 +1356,11 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) {
/* mark it as used before releasing the lock */
chosen->data = data; /* own it! */
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
*usethis = chosen;
return TRUE; /* yes, we found one to use! */
}
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
@@ -1679,11 +1575,25 @@ static bool is_ASCII_name(const char *hostname)
}
/*
- * Perform any necessary IDN conversion of hostname
+ * Strip single trailing dot in the hostname,
+ * primarily for SNI and http host header.
*/
-static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
+static void strip_trailing_dot(struct hostname *host)
{
size_t len;
+ if(!host || !host->name)
+ return;
+ len = strlen(host->name);
+ if(len && (host->name[len-1] == '.'))
+ host->name[len-1] = 0;
+}
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+static CURLcode idnconvert_hostname(struct connectdata *conn,
+ struct hostname *host)
+{
struct Curl_easy *data = conn->data;
#ifndef USE_LIBIDN2
@@ -1696,12 +1606,6 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
/* set the name we use to display the host name */
host->dispname = host->name;
- len = strlen(host->name);
- if(len && (host->name[len-1] == '.'))
- /* strip off a single trailing dot if present, primarily for SNI but
- there's no use for it */
- host->name[len-1] = 0;
-
/* Check name for non-ASCII and convert hostname to ACE form if we can */
if(!is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN2
@@ -1743,22 +1647,13 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
infof(data, "IDN support not present, can't parse Unicode domains\n");
#endif
}
- {
- char *hostp;
- for(hostp = host->name; *hostp; hostp++) {
- if(*hostp <= 32) {
- failf(data, "Host name '%s' contains bad letter", host->name);
- return CURLE_URL_MALFORMAT;
- }
- }
- }
return CURLE_OK;
}
/*
- * Frees data allocated by fix_hostname()
+ * Frees data allocated by idnconvert_hostname()
*/
-static void free_fixed_hostname(struct hostname *host)
+static void free_idnconverted_hostname(struct hostname *host)
{
#if defined(USE_LIBIDN2)
if(host->encalloc) {
@@ -1849,16 +1744,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->http_proxy.proxytype = data->set.proxytype;
conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
-#ifdef CURL_DISABLE_PROXY
-
- conn->bits.proxy = FALSE;
- conn->bits.httpproxy = FALSE;
- conn->bits.socksproxy = FALSE;
- conn->bits.proxy_user_passwd = FALSE;
- conn->bits.tunnel_proxy = FALSE;
-
-#else /* CURL_DISABLE_PROXY */
-
+#if !defined(CURL_DISABLE_PROXY)
/* note that these two proxy bits are now just on what looks to be
requested, they may be altered down the road */
conn->bits.proxy = (data->set.str[STRING_PROXY] &&
@@ -1879,13 +1765,13 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->bits.proxy_user_passwd =
(data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
-
#endif /* CURL_DISABLE_PROXY */
conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
+#ifndef CURL_DISABLE_FTP
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
-
+#endif
conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
@@ -1893,28 +1779,16 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
data->set.proxy_ssl.primary.verifystatus;
conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
-
conn->ip_version = data->set.ipver;
+ conn->bits.connect_only = data->set.connect_only;
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
defined(NTLM_WB_ENABLED)
conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
- conn->ntlm_auth_hlpr_pid = 0;
- conn->challenge_header = NULL;
- conn->response_header = NULL;
#endif
- if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
- !conn->master_buffer) {
- /* Allocate master_buffer to be used for HTTP/1 pipelining */
- conn->master_buffer = calloc(MASTERBUF_SIZE, sizeof(char));
- if(!conn->master_buffer)
- goto error;
- }
-
- /* Initialize the pipeline lists */
- Curl_llist_init(&conn->send_pipe, (curl_llist_dtor) llist_dtor);
- Curl_llist_init(&conn->recv_pipe, (curl_llist_dtor) llist_dtor);
+ /* Initialize the easy handle list */
+ Curl_llist_init(&conn->easyq, (curl_llist_dtor) llist_dtor);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CLEAR;
@@ -1937,10 +1811,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
return conn;
error:
- Curl_llist_destroy(&conn->send_pipe, NULL);
- Curl_llist_destroy(&conn->recv_pipe, NULL);
-
- free(conn->master_buffer);
+ Curl_llist_destroy(&conn->easyq, NULL);
free(conn->localdev);
#ifdef USE_SSL
free(conn->ssl_extra);
@@ -2023,10 +1894,16 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
CURLUcode uc;
char *hostname;
- Curl_up_free(data); /* cleanup previous leftovers first */
+ up_free(data); /* cleanup previous leftovers first */
/* parse the URL */
- uh = data->state.uh = curl_url();
+ if(data->set.uh) {
+ uh = data->state.uh = curl_url_dup(data->set.uh);
+ }
+ else {
+ uh = data->state.uh = curl_url();
+ }
+
if(!uh)
return CURLE_OUT_OF_MEMORY;
@@ -2043,14 +1920,18 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
data->change.url_alloc = TRUE;
}
- uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
+ if(!data->set.uh) {
+ uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
(data->set.disallow_username_in_url ?
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
- if(uc)
- return Curl_uc_to_curlcode(uc);
+ if(uc) {
+ DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
+ return Curl_uc_to_curlcode(uc);
+ }
+ }
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
if(uc)
@@ -2121,61 +2002,40 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
hostname = (char *)"";
if(hostname[0] == '[') {
- /* This looks like an IPv6 address literal. See if there is an address
+ /* This looks like an IPv6 address literal. See if there is an address
scope. */
- char *percent = strchr(++hostname, '%');
+ char *zoneid;
+ size_t hlen;
+ uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
conn->bits.ipv6_ip = TRUE;
- if(percent) {
- unsigned int identifier_offset = 3;
+
+ /* cut off the brackets! */
+ hostname++;
+ hlen = strlen(hostname);
+ hostname[hlen - 1] = 0;
+ if(!uc && zoneid) {
char *endp;
unsigned long scope;
- if(strncmp("%25", percent, 3) != 0) {
- infof(data,
- "Please URL encode %% as %%25, see RFC 6874.\n");
- identifier_offset = 1;
- }
- scope = strtoul(percent + identifier_offset, &endp, 10);
- if(*endp == ']') {
- /* The address scope was well formed. Knock it out of the
- hostname. */
- memmove(percent, endp, strlen(endp) + 1);
+ scope = strtoul(zoneid, &endp, 10);
+ if(!*endp && (scope < UINT_MAX)) {
+ /* A plain number, use it direcly as a scope id. */
conn->scope_id = (unsigned int)scope;
}
+#ifdef HAVE_IF_NAMETOINDEX
else {
/* Zone identifier is not numeric */
-#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX)
- char ifname[IFNAMSIZ + 2];
- char *square_bracket;
unsigned int scopeidx = 0;
- strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2);
- /* Ensure nullbyte termination */
- ifname[IFNAMSIZ + 1] = '\0';
- square_bracket = strchr(ifname, ']');
- if(square_bracket) {
- /* Remove ']' */
- *square_bracket = '\0';
- scopeidx = if_nametoindex(ifname);
- if(scopeidx == 0) {
- infof(data, "Invalid network interface: %s; %s\n", ifname,
- strerror(errno));
- }
- }
- if(scopeidx > 0) {
- char *p = percent + identifier_offset + strlen(ifname);
-
- /* Remove zone identifier from hostname */
- memmove(percent, p, strlen(p) + 1);
- conn->scope_id = scopeidx;
- }
+ scopeidx = if_nametoindex(zoneid);
+ if(!scopeidx)
+ infof(data, "Invalid zoneid id: %s; %s\n", zoneid,
+ strerror(errno));
else
-#endif /* HAVE_NET_IF_H && IFNAMSIZ */
- infof(data, "Invalid IPv6 address format\n");
+ conn->scope_id = scopeidx;
+
}
+#endif /* HAVE_IF_NAMETOINDEX */
+ free(zoneid);
}
- percent = strchr(hostname, ']');
- if(percent)
- /* terminate IPv6 numerical at end bracket */
- *percent = 0;
}
/* make sure the connect struct gets its own copy of the host name */
@@ -2191,6 +2051,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OK;
}
+
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
@@ -2437,46 +2298,55 @@ static CURLcode parse_proxy(struct Curl_easy *data,
struct connectdata *conn, char *proxy,
curl_proxytype proxytype)
{
- char *prox_portno;
- char *endofprot;
-
- /* We use 'proxyptr' to point to the proxy name from now on... */
- char *proxyptr;
char *portptr;
- char *atsign;
long port = -1;
char *proxyuser = NULL;
char *proxypasswd = NULL;
+ char *host;
bool sockstype;
+ CURLUcode uc;
+ struct proxy_info *proxyinfo;
+ CURLU *uhp = curl_url();
+ CURLcode result = CURLE_OK;
+ char *scheme = NULL;
- /* We do the proxy host string parsing here. We want the host name and the
- * port name. Accept a protocol:// prefix
- */
+ /* When parsing the proxy, allowing non-supported schemes since we have
+ these made up ones for proxies. Guess scheme for URLs without it. */
+ uc = curl_url_set(uhp, CURLUPART_URL, proxy,
+ CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
+ if(!uc) {
+ /* parsed okay as a URL */
+ uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
+ if(uc) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- /* Parse the protocol part if present */
- endofprot = strstr(proxy, "://");
- if(endofprot) {
- proxyptr = endofprot + 3;
- if(checkprefix("https", proxy))
+ if(strcasecompare("https", scheme))
proxytype = CURLPROXY_HTTPS;
- else if(checkprefix("socks5h", proxy))
+ else if(strcasecompare("socks5h", scheme))
proxytype = CURLPROXY_SOCKS5_HOSTNAME;
- else if(checkprefix("socks5", proxy))
+ else if(strcasecompare("socks5", scheme))
proxytype = CURLPROXY_SOCKS5;
- else if(checkprefix("socks4a", proxy))
+ else if(strcasecompare("socks4a", scheme))
proxytype = CURLPROXY_SOCKS4A;
- else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy))
+ else if(strcasecompare("socks4", scheme) ||
+ strcasecompare("socks", scheme))
proxytype = CURLPROXY_SOCKS4;
- else if(checkprefix("http:", proxy))
+ else if(strcasecompare("http", scheme))
; /* leave it as HTTP or HTTP/1.0 */
else {
/* Any other xxx:// reject! */
failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
- return CURLE_COULDNT_CONNECT;
+ result = CURLE_COULDNT_CONNECT;
+ goto error;
}
}
- else
- proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
+ else {
+ failf(data, "Unsupported proxy syntax in \'%s\'", proxy);
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ goto error;
+ }
#ifdef USE_SSL
if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
@@ -2484,93 +2354,44 @@ static CURLcode parse_proxy(struct Curl_easy *data,
if(proxytype == CURLPROXY_HTTPS) {
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
"HTTPS-proxy support.", proxy);
- return CURLE_NOT_BUILT_IN;
+ result = CURLE_NOT_BUILT_IN;
+ goto error;
}
- sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
- proxytype == CURLPROXY_SOCKS5 ||
- proxytype == CURLPROXY_SOCKS4A ||
- proxytype == CURLPROXY_SOCKS4;
-
- /* Is there a username and password given in this proxy url? */
- atsign = strchr(proxyptr, '@');
- if(atsign) {
- CURLcode result =
- Curl_parse_login_details(proxyptr, atsign - proxyptr,
- &proxyuser, &proxypasswd, NULL);
- if(result)
- return result;
- proxyptr = atsign + 1;
- }
+ sockstype =
+ proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+ proxytype == CURLPROXY_SOCKS5 ||
+ proxytype == CURLPROXY_SOCKS4A ||
+ proxytype == CURLPROXY_SOCKS4;
- /* start scanning for port number at this point */
- portptr = proxyptr;
+ proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
+ proxyinfo->proxytype = proxytype;
- /* detect and extract RFC6874-style IPv6-addresses */
- if(*proxyptr == '[') {
- char *ptr = ++proxyptr; /* advance beyond the initial bracket */
- while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
- ptr++;
- if(*ptr == '%') {
- /* There might be a zone identifier */
- if(strncmp("%25", ptr, 3))
- infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
- ptr++;
- /* Allow unreserved characters as defined in RFC 3986 */
- while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
- (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
- ptr++;
+ /* Is there a username and password given in this proxy url? */
+ curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
+ curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
+ if(proxyuser || proxypasswd) {
+ Curl_safefree(proxyinfo->user);
+ proxyinfo->user = proxyuser;
+ Curl_safefree(proxyinfo->passwd);
+ if(!proxypasswd) {
+ proxypasswd = strdup("");
+ if(!proxypasswd) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
}
- if(*ptr == ']')
- /* yeps, it ended nicely with a bracket as well */
- *ptr++ = 0;
- else
- infof(data, "Invalid IPv6 address format\n");
- portptr = ptr;
- /* Note that if this didn't end with a bracket, we still advanced the
- * proxyptr first, but I can't see anything wrong with that as no host
- * name nor a numeric can legally start with a bracket.
- */
+ proxyinfo->passwd = proxypasswd;
+ conn->bits.proxy_user_passwd = TRUE; /* enable it */
}
- /* Get port number off proxy.server.com:1080 */
- prox_portno = strchr(portptr, ':');
- if(prox_portno) {
- char *endp = NULL;
+ curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
- *prox_portno = 0x0; /* cut off number from host name */
- prox_portno ++;
- /* now set the local port number */
- port = strtol(prox_portno, &endp, 10);
- if((endp && *endp && (*endp != '/') && (*endp != ' ')) ||
- (port < 0) || (port > 65535)) {
- /* meant to detect for example invalid IPv6 numerical addresses without
- brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only
- because we then allow "URL style" with the number followed by a
- slash, used in curl test cases already. Space is also an acceptable
- terminating symbol. */
- infof(data, "No valid port number in proxy string (%s)\n",
- prox_portno);
- }
- else
- conn->port = port;
+ if(portptr) {
+ port = strtol(portptr, NULL, 10);
+ free(portptr);
}
else {
- if(proxyptr[0]=='/') {
- /* If the first character in the proxy string is a slash, fail
- immediately. The following code will otherwise clear the string which
- will lead to code running as if no proxy was set! */
- Curl_safefree(proxyuser);
- Curl_safefree(proxypasswd);
- return CURLE_COULDNT_RESOLVE_PROXY;
- }
-
- /* without a port number after the host name, some people seem to use
- a slash so we strip everything from the first slash */
- atsign = strchr(proxyptr, '/');
- if(atsign)
- *atsign = '\0'; /* cut off path part from host name */
-
if(data->set.proxyport)
/* None given in the proxy string, then get the default one if it is
given */
@@ -2582,57 +2403,32 @@ static CURLcode parse_proxy(struct Curl_easy *data,
port = CURL_DEFAULT_PROXY_PORT;
}
}
-
- if(*proxyptr) {
- struct proxy_info *proxyinfo =
- sockstype ? &conn->socks_proxy : &conn->http_proxy;
- proxyinfo->proxytype = proxytype;
-
- if(proxyuser) {
- /* found user and password, rip them out. note that we are unescaping
- them, as there is otherwise no way to have a username or password
- with reserved characters like ':' in them. */
- Curl_safefree(proxyinfo->user);
- proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL);
- Curl_safefree(proxyuser);
-
- if(!proxyinfo->user) {
- Curl_safefree(proxypasswd);
- return CURLE_OUT_OF_MEMORY;
- }
-
- Curl_safefree(proxyinfo->passwd);
- if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
- proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL);
- else
- proxyinfo->passwd = strdup("");
- Curl_safefree(proxypasswd);
-
- if(!proxyinfo->passwd)
- return CURLE_OUT_OF_MEMORY;
-
- conn->bits.proxy_user_passwd = TRUE; /* enable it */
- }
-
- if(port >= 0) {
- proxyinfo->port = port;
- if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
- conn->port = port;
- }
-
- /* now, clone the cleaned proxy host name */
- Curl_safefree(proxyinfo->host.rawalloc);
- proxyinfo->host.rawalloc = strdup(proxyptr);
- proxyinfo->host.name = proxyinfo->host.rawalloc;
-
- if(!proxyinfo->host.rawalloc)
- return CURLE_OUT_OF_MEMORY;
+ if(port >= 0) {
+ proxyinfo->port = port;
+ if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
+ conn->port = port;
}
- Curl_safefree(proxyuser);
- Curl_safefree(proxypasswd);
+ /* now, clone the proxy host name */
+ uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
+ if(uc) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ Curl_safefree(proxyinfo->host.rawalloc);
+ proxyinfo->host.rawalloc = host;
+ if(host[0] == '[') {
+ /* this is a numerical IPv6, strip off the brackets */
+ size_t len = strlen(host);
+ host[len-1] = 0; /* clear the trailing bracket */
+ host++;
+ }
+ proxyinfo->host.name = host;
- return CURLE_OK;
+ error:
+ free(scheme);
+ curl_url_cleanup(uhp);
+ return result;
}
/*
@@ -2979,7 +2775,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
char portbuf[16];
CURLUcode uc;
conn->remote_port = (unsigned short)data->set.use_port;
- snprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
+ msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
if(uc)
return CURLE_OUT_OF_MEMORY;
@@ -2999,6 +2795,20 @@ static CURLcode override_login(struct Curl_easy *data,
bool user_changed = FALSE;
bool passwd_changed = FALSE;
CURLUcode uc;
+
+ if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
+ /* ignore user+password in the URL */
+ if(*userp) {
+ Curl_safefree(*userp);
+ user_changed = TRUE;
+ }
+ if(*passwdp) {
+ Curl_safefree(*passwdp);
+ passwd_changed = TRUE;
+ }
+ conn->bits.user_passwd = FALSE; /* disable user+password */
+ }
+
if(data->set.str[STRING_USERNAME]) {
free(*userp);
*userp = strdup(data->set.str[STRING_USERNAME]);
@@ -3025,16 +2835,15 @@ static CURLcode override_login(struct Curl_easy *data,
}
conn->bits.netrc = FALSE;
- if(data->set.use_netrc != CURL_NETRC_IGNORED) {
- char *nuser = NULL;
- char *npasswd = NULL;
+ if(data->set.use_netrc != CURL_NETRC_IGNORED &&
+ (!*userp || !**userp || !*passwdp || !**passwdp)) {
+ bool netrc_user_changed = FALSE;
+ bool netrc_passwd_changed = FALSE;
int ret;
- if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
- nuser = *userp; /* to separate otherwise identical machines */
-
ret = Curl_parsenetrc(conn->host.name,
- &nuser, &npasswd,
+ userp, passwdp,
+ &netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
infof(data, "Couldn't find host %s in the "
@@ -3051,31 +2860,11 @@ static CURLcode override_login(struct Curl_easy *data,
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
- if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
- /* prefer credentials outside netrc */
- if(nuser && !*userp) {
- free(*userp);
- *userp = nuser;
- user_changed = TRUE;
- }
- if(npasswd && !*passwdp) {
- free(*passwdp);
- *passwdp = npasswd;
- passwd_changed = TRUE;
- }
+ if(netrc_user_changed) {
+ user_changed = TRUE;
}
- else {
- /* prefer netrc credentials */
- if(nuser) {
- free(*userp);
- *userp = nuser;
- user_changed = TRUE;
- }
- if(npasswd) {
- free(*passwdp);
- *passwdp = npasswd;
- passwd_changed = TRUE;
- }
+ if(netrc_passwd_changed) {
+ passwd_changed = TRUE;
}
}
}
@@ -3351,6 +3140,34 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
conn_to_host = conn_to_host->next;
}
+#ifdef USE_ALTSVC
+ if(data->asi && !host && (port == -1) &&
+ (conn->handler->protocol == CURLPROTO_HTTPS)) {
+ /* no connect_to match, try alt-svc! */
+ const char *nhost;
+ int nport;
+ enum alpnid nalpnid;
+ bool hit;
+ host = conn->host.rawalloc;
+ hit = Curl_altsvc_lookup(data->asi,
+ ALPN_h1, host, conn->remote_port, /* from */
+ &nalpnid, &nhost, &nport /* to */);
+ if(hit) {
+ char *hostd = strdup((char *)nhost);
+ if(!hostd)
+ return CURLE_OUT_OF_MEMORY;
+ conn->conn_to_host.rawalloc = hostd;
+ conn->conn_to_host.name = hostd;
+ conn->bits.conn_to_host = TRUE;
+ conn->conn_to_port = nport;
+ conn->bits.conn_to_port = TRUE;
+ infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
+ Curl_alpnid2str(ALPN_h1), host, conn->remote_port,
+ Curl_alpnid2str(nalpnid), hostd, nport);
+ }
+ }
+#endif
+
return result;
}
@@ -3364,12 +3181,14 @@ static CURLcode resolve_server(struct Curl_easy *data,
CURLcode result = CURLE_OK;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ DEBUGASSERT(conn);
+ DEBUGASSERT(data);
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
if(conn->bits.reuse)
/* We're reusing the connection - no need to resolve anything, and
- fix_hostname() was called already in create_conn() for the re-use
+ idnconvert_hostname() was called already in create_conn() for the re-use
case. */
*async = FALSE;
@@ -3424,7 +3243,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
conn->port = conn->remote_port;
/* Resolve target host right on */
- rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
+ 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,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
@@ -3445,7 +3267,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
&conn->socks_proxy.host : &conn->http_proxy.host;
/* resolve proxy */
- rc = Curl_resolv_timeout(conn, host->name, (int)conn->port,
+ 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,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
@@ -3475,8 +3300,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
- free_fixed_hostname(&old_conn->http_proxy.host);
- free_fixed_hostname(&old_conn->socks_proxy.host);
+ free_idnconverted_hostname(&old_conn->http_proxy.host);
+ free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
@@ -3520,14 +3345,18 @@ static void reuse_conn(struct connectdata *old_conn,
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
- free_fixed_hostname(&conn->host);
- free_fixed_hostname(&conn->conn_to_host);
+ free_idnconverted_hostname(&conn->host);
+ free_idnconverted_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host = old_conn->host;
conn->conn_to_host = old_conn->conn_to_host;
conn->conn_to_port = old_conn->conn_to_port;
conn->remote_port = old_conn->remote_port;
+ Curl_safefree(conn->hostname_resolve);
+
+ conn->hostname_resolve = old_conn->hostname_resolve;
+ old_conn->hostname_resolve = NULL;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@@ -3545,11 +3374,7 @@ static void reuse_conn(struct connectdata *old_conn,
Curl_safefree(old_conn->http_proxy.passwd);
Curl_safefree(old_conn->socks_proxy.passwd);
Curl_safefree(old_conn->localdev);
-
- Curl_llist_destroy(&old_conn->send_pipe, NULL);
- Curl_llist_destroy(&old_conn->recv_pipe, NULL);
-
- Curl_safefree(old_conn->master_buffer);
+ Curl_llist_destroy(&old_conn->easyq, NULL);
#ifdef USE_UNIX_SOCKETS
Curl_safefree(old_conn->unix_domain_socket);
@@ -3587,6 +3412,7 @@ static CURLcode create_conn(struct Curl_easy *data,
size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
*async = FALSE;
+ *in_connect = NULL;
/*************************************************************
* Check input data
@@ -3677,30 +3503,30 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
/*************************************************************
- * IDN-fix the hostnames
+ * IDN-convert the hostnames
*************************************************************/
- result = fix_hostname(conn, &conn->host);
+ result = idnconvert_hostname(conn, &conn->host);
if(result)
goto out;
if(conn->bits.conn_to_host) {
- result = fix_hostname(conn, &conn->conn_to_host);
+ result = idnconvert_hostname(conn, &conn->conn_to_host);
if(result)
goto out;
}
if(conn->bits.httpproxy) {
- result = fix_hostname(conn, &conn->http_proxy.host);
+ result = idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
goto out;
}
if(conn->bits.socksproxy) {
- result = fix_hostname(conn, &conn->socks_proxy.host);
+ result = idnconvert_hostname(conn, &conn->socks_proxy.host);
if(result)
goto out;
}
/*************************************************************
* Check whether the host and the "connect to host" are equal.
- * Do this after the hostnames have been IDN-fixed.
+ * Do this after the hostnames have been IDN-converted.
*************************************************************/
if(conn->bits.conn_to_host &&
strcasecompare(conn->conn_to_host.name, conn->host.name)) {
@@ -3752,7 +3578,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Setup a "faked" transfer that'll do nothing */
if(!result) {
- conn->data = data;
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
@@ -3769,9 +3594,8 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)conn->handler->done(conn, result, FALSE);
goto out;
}
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
- -1, NULL); /* no upload */
+ Curl_attach_connnection(data, conn);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
/* since we skip do_init() */
@@ -3857,19 +3681,20 @@ static CURLcode create_conn(struct Curl_easy *data,
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
we only acknowledge this option if this is not a re-used connection
already (which happens due to follow-location or during a HTTP
- authentication phase). */
- if(data->set.reuse_fresh && !data->state.this_is_a_follow)
+ authentication phase). CONNECT_ONLY transfers also refuse reuse. */
+ if((data->set.reuse_fresh && !data->state.this_is_a_follow) ||
+ data->set.connect_only)
reuse = FALSE;
else
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
/* If we found a reusable connection that is now marked as in use, we may
- still want to open a new connection if we are pipelining. */
- if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) {
- size_t pipelen = conn_temp->send_pipe.size + conn_temp->recv_pipe.size;
- if(pipelen > 0) {
- infof(data, "Found connection %ld, with requests in the pipe (%zu)\n",
- conn_temp->connection_id, pipelen);
+ still want to open a new connection if we are multiplexing. */
+ if(reuse && !force_reuse && IsMultiplexingPossible(data, conn_temp)) {
+ size_t multiplexed = CONN_INUSE(conn_temp);
+ if(multiplexed > 0) {
+ infof(data, "Found connection %ld, with %zu requests on it\n",
+ conn_temp->connection_id, multiplexed);
if(Curl_conncache_bundle_size(conn_temp) < max_host_connections &&
Curl_conncache_size(data) < max_total_connections) {
@@ -3919,7 +3744,7 @@ static CURLcode create_conn(struct Curl_easy *data,
}
if(waitpipe)
- /* There is a connection that *might* become usable for pipelining
+ /* There is a connection that *might* become usable for multiplexing
"soon", and we wait for that */
connections_available = FALSE;
else {
@@ -3933,7 +3758,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* The bundle is full. Extract the oldest connection. */
conn_candidate = Curl_conncache_extract_bundle(data, bundle);
- Curl_conncache_unlock(conn);
+ Curl_conncache_unlock(data);
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate,
@@ -3945,7 +3770,7 @@ static CURLcode create_conn(struct Curl_easy *data,
}
}
else
- Curl_conncache_unlock(conn);
+ Curl_conncache_unlock(data);
}
@@ -4028,6 +3853,15 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
result = resolve_server(data, conn, async);
+ /* Strip trailing dots. resolve_server copied the name. */
+ strip_trailing_dot(&conn->host);
+ if(conn->bits.httpproxy)
+ strip_trailing_dot(&conn->http_proxy.host);
+ if(conn->bits.socksproxy)
+ strip_trailing_dot(&conn->socks_proxy.host);
+ if(conn->bits.conn_to_host)
+ strip_trailing_dot(&conn->conn_to_host);
+
out:
return result;
}
@@ -4105,11 +3939,11 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
CURLcode Curl_connect(struct Curl_easy *data,
- struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
{
CURLcode result;
+ struct connectdata *conn;
*asyncp = FALSE; /* assume synchronous resolves by default */
@@ -4119,30 +3953,31 @@ CURLcode Curl_connect(struct Curl_easy *data,
data->req.maxdownload = -1;
/* call the stuff that needs to be called */
- result = create_conn(data, in_connect, asyncp);
+ result = create_conn(data, &conn, asyncp);
if(!result) {
- if(CONN_INUSE(*in_connect))
- /* pipelining */
+ if(CONN_INUSE(conn))
+ /* multiplexed */
*protocol_done = TRUE;
else if(!*asyncp) {
/* 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(*in_connect, protocol_done);
+ result = Curl_setup_conn(conn, protocol_done);
}
}
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
- *in_connect = NULL;
return result;
}
- else if(result && *in_connect) {
+ else if(result && conn) {
/* We're not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
- Curl_disconnect(data, *in_connect, TRUE);
- *in_connect = NULL; /* return a NULL */
+ Curl_disconnect(data, conn, TRUE);
}
+ else if(!result && !data->conn)
+ /* FILE: transfers already have the connection attached */
+ Curl_attach_connnection(data, conn);
return result;
}
diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h
index 095d63833..4db9e8653 100644
--- a/Utilities/cmcurl/lib/url.h
+++ b/Utilities/cmcurl/lib/url.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -52,8 +52,7 @@ void Curl_freeset(struct Curl_easy * data);
void Curl_up_free(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
- bool *async, bool *protocol_connect);
+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_protocol_connect(struct connectdata *conn, bool *done);
@@ -72,14 +71,7 @@ int Curl_doing_getsock(struct connectdata *conn,
CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
-
-int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
- struct curl_llist *pipeline);
-/* remove the specified connection from all (possible) pipelines and related
- queues */
-void Curl_getoff_all_pipelines(struct Curl_easy *data,
- struct connectdata *conn);
-
+void Curl_close_connections(struct Curl_easy *data);
CURLcode Curl_upkeep(struct conncache *conn_cache, void *data);
const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
diff --git a/Utilities/cmcurl/lib/urlapi-int.h b/Utilities/cmcurl/lib/urlapi-int.h
index a57d2e22b..5f059c203 100644
--- a/Utilities/cmcurl/lib/urlapi-int.h
+++ b/Utilities/cmcurl/lib/urlapi-int.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,12 +22,16 @@
*
***************************************************************************/
#include "curl_setup.h"
-/* scheme is not URL encoded, the longest libcurl supported ones are 6
- letters */
-#define MAX_SCHEME_LEN 8
+/* scheme is not URL encoded, the longest libcurl supported ones are... */
+#define MAX_SCHEME_LEN 40
bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
char *Curl_concat_url(const char *base, const char *relurl);
size_t Curl_strlen_url(const char *url, bool relative);
void Curl_strcpy_url(char *output, const char *url, bool relative);
+
+#ifdef DEBUGBUILD
+CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname);
+#endif
+
#endif /* HEADER_CURL_URLAPI_INT_H */
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index c53e52343..d07e4f5df 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -56,6 +56,7 @@ struct Curl_URL {
char *password;
char *options; /* IMAP only? */
char *host;
+ char *zoneid; /* for numerical IPv6 addresses */
char *port;
char *path;
char *query;
@@ -74,6 +75,7 @@ static void free_urlhandle(struct Curl_URL *u)
free(u->password);
free(u->options);
free(u->host);
+ free(u->zoneid);
free(u->port);
free(u->path);
free(u->query);
@@ -135,7 +137,7 @@ static bool urlchar_needs_escaping(int c)
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
-size_t Curl_strlen_url(const char *url, bool relative)
+static size_t strlen_url(const char *url, bool relative)
{
const unsigned char *ptr;
size_t newlen = 0;
@@ -177,7 +179,7 @@ size_t Curl_strlen_url(const char *url, bool relative)
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
-void Curl_strcpy_url(char *output, const char *url, bool relative)
+static void strcpy_url(char *output, const char *url, bool relative)
{
/* we must add this with whitespace-replacing */
bool left = TRUE;
@@ -203,7 +205,7 @@ void Curl_strcpy_url(char *output, const char *url, bool relative)
/* FALLTHROUGH */
default:
if(urlchar_needs_escaping(*iptr)) {
- snprintf(optr, 4, "%%%02x", *iptr);
+ msnprintf(optr, 4, "%%%02x", *iptr);
optr += 3;
}
else
@@ -238,7 +240,7 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
#endif
for(i = 0; i < buflen && url[i]; ++i) {
char s = url[i];
- if(s == ':') {
+ if((s == ':') && (url[i + 1] == '/')) {
if(buf)
buf[i] = 0;
return TRUE;
@@ -262,7 +264,7 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
* The returned pointer must be freed by the caller unless NULL
* (returns NULL on out of memory).
*/
-char *Curl_concat_url(const char *base, const char *relurl)
+static char *concat_url(const char *base, const char *relurl)
{
/***
TRY to append this new path to the old URL
@@ -386,7 +388,7 @@ char *Curl_concat_url(const char *base, const char *relurl)
letter we replace each space with %20 while it is replaced with '+'
on the right side of the '?' letter.
*/
- newlen = Curl_strlen_url(useurl, !host_changed);
+ newlen = strlen_url(useurl, !host_changed);
urllen = strlen(url_clone);
@@ -408,7 +410,7 @@ char *Curl_concat_url(const char *base, const char *relurl)
newest[urllen++]='/';
/* then append the new piece on the right side */
- Curl_strcpy_url(&newest[urllen], useurl, !host_changed);
+ strcpy_url(&newest[urllen], useurl, !host_changed);
free(url_clone);
@@ -488,19 +490,40 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
return result;
}
-static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
+UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
{
- char *portptr;
+ char *portptr = NULL;
char endbracket;
int len;
- if((1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.%%]%c%n",
- &endbracket, &len)) &&
- (']' == endbracket)) {
- /* this is a RFC2732-style specified IP-address */
- portptr = &hostname[len];
- if (*portptr != ':')
+ /*
+ * Find the end of an IPv6 address, either on the ']' ending bracket or
+ * a percent-encoded zone index.
+ */
+ if(1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.]%c%n",
+ &endbracket, &len)) {
+ if(']' == endbracket)
+ portptr = &hostname[len];
+ else if('%' == endbracket) {
+ int zonelen = len;
+ if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
+ if(']' != endbracket)
+ return CURLUE_MALFORMED_INPUT;
+ portptr = &hostname[--zonelen + len + 1];
+ }
+ else
+ return CURLUE_MALFORMED_INPUT;
+ }
+ else
return CURLUE_MALFORMED_INPUT;
+
+ /* this is a RFC2732-style specified IP-address */
+ if(portptr && *portptr) {
+ if(*portptr != ':')
+ return CURLUE_MALFORMED_INPUT;
+ }
+ else
+ portptr = NULL;
}
else
portptr = strchr(hostname, ':');
@@ -510,6 +533,14 @@ static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
long port;
char portbuf[7];
+ /* 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. */
+ if(!portptr[1]) {
+ *portptr = '\0';
+ return CURLUE_OK;
+ }
+
if(!ISDIGIT(portptr[1]))
return CURLUE_BAD_PORT_NUMBER;
@@ -523,22 +554,14 @@ static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
if(rest[0])
return CURLUE_BAD_PORT_NUMBER;
- if(rest != &portptr[1]) {
- *portptr++ = '\0'; /* cut off the name there */
- *rest = 0;
- /* generate a new to get rid of leading zeroes etc */
- snprintf(portbuf, sizeof(portbuf), "%ld", port);
- u->portnum = port;
- u->port = strdup(portbuf);
- if(!u->port)
- return CURLUE_OUT_OF_MEMORY;
- }
- else {
- /* 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 and Chrome both do that. */
- *portptr = '\0';
- }
+ *portptr++ = '\0'; /* cut off the name there */
+ *rest = 0;
+ /* generate a new port number string to get rid of leading zeroes etc */
+ msnprintf(portbuf, sizeof(portbuf), "%ld", port);
+ u->portnum = port;
+ u->port = strdup(portbuf);
+ if(!u->port)
+ return CURLUE_OUT_OF_MEMORY;
}
return CURLUE_OK;
@@ -547,15 +570,15 @@ static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
/* scan for byte values < 31 or 127 */
static CURLUcode junkscan(char *part)
{
- char badbytes[]={
- /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x7f,
- 0x00 /* zero terminate */
- };
if(part) {
+ static const char badbytes[]={
+ /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x7f,
+ 0x00 /* zero terminate */
+ };
size_t n = strlen(part);
size_t nfine = strcspn(part, badbytes);
if(nfine != n)
@@ -566,25 +589,45 @@ static CURLUcode junkscan(char *part)
return CURLUE_OK;
}
-static CURLUcode hostname_check(char *hostname, unsigned int flags)
+static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
{
const char *l = NULL; /* accepted characters */
size_t len;
size_t hlen = strlen(hostname);
- (void)flags;
if(hostname[0] == '[') {
hostname++;
- l = "0123456789abcdefABCDEF::.%";
+ l = "0123456789abcdefABCDEF::.";
hlen -= 2;
}
if(l) {
/* only valid letters are ok */
len = strspn(hostname, l);
- if(hlen != len)
- /* hostname with bad content */
- return CURLUE_MALFORMED_INPUT;
+ if(hlen != len) {
+ if(hostname[len] == '%') {
+ /* this could now be '%[zone id]' */
+ char zoneid[16];
+ int i = 0;
+ char *h = &hostname[len + 1];
+ /* pass '25' if present and is a url encoded percent sign */
+ if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
+ h += 2;
+ while(*h && (*h != ']') && (i < 15))
+ zoneid[i++] = *h++;
+ if(!i || (']' != *h))
+ return CURLUE_MALFORMED_INPUT;
+ zoneid[i] = 0;
+ u->zoneid = strdup(zoneid);
+ if(!u->zoneid)
+ return CURLUE_OUT_OF_MEMORY;
+ hostname[len] = ']'; /* insert end bracket */
+ hostname[len + 1] = 0; /* terminate the hostname */
+ }
+ else
+ return CURLUE_MALFORMED_INPUT;
+ /* hostname is fine */
+ }
}
else {
/* letters from the second string is not ok */
@@ -593,6 +636,8 @@ static CURLUcode hostname_check(char *hostname, unsigned int flags)
/* hostname with bad content */
return CURLUE_MALFORMED_INPUT;
}
+ if(!hostname[0])
+ return CURLUE_NO_HOST;
return CURLUE_OK;
}
@@ -607,7 +652,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
char *fragment = NULL;
CURLUcode result;
bool url_has_scheme = FALSE;
- char schemebuf[MAX_SCHEME_LEN];
+ char schemebuf[MAX_SCHEME_LEN + 1];
char *schemep = NULL;
size_t schemelen = 0;
size_t urllen;
@@ -621,6 +666,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
************************************************************/
/* allocate scratch area */
urllen = strlen(url);
+ if(urllen > CURL_MAX_INPUT_LENGTH)
+ /* excessive input length */
+ return CURLUE_MALFORMED_INPUT;
+
path = u->scratch = malloc(urllen * 2 + 2);
if(!path)
return CURLUE_OUT_OF_MEMORY;
@@ -827,11 +876,11 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(result)
return result;
- result = parse_port(u, hostname);
+ result = Curl_parse_port(u, hostname);
if(result)
return result;
- result = hostname_check(hostname, flags);
+ result = hostname_check(u, hostname);
if(result)
return result;
@@ -840,7 +889,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
return CURLUE_OUT_OF_MEMORY;
}
- if(query && query[0]) {
+ if(query) {
u->query = strdup(query);
if(!u->query)
return CURLUE_OUT_OF_MEMORY;
@@ -950,6 +999,9 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
ptr = u->host;
ifmissing = CURLUE_NO_HOST;
break;
+ case CURLUPART_ZONEID:
+ ptr = u->zoneid;
+ break;
case CURLUPART_PORT:
ptr = u->port;
ifmissing = CURLUE_NO_PORT;
@@ -960,7 +1012,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
if(h) {
- snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
ptr = portbuf;
}
}
@@ -996,6 +1048,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
char *scheme;
char *options = u->options;
char *port = u->port;
+ char *allochost = NULL;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
@@ -1019,7 +1072,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
/* there's no stored port number, but asked to deliver
a default one for the scheme */
if(h) {
- snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
port = portbuf;
}
}
@@ -1034,6 +1087,18 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
+ if((u->host[0] == '[') && u->zoneid) {
+ /* make it '[ host %25 zoneid ]' */
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 3 + strlen(u->zoneid) + 1;
+ allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+ memcpy(allochost, u->host, hostlen - 1);
+ msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
+ "%%25%s]", u->zoneid);
+ }
+
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
scheme,
u->user ? u->user : "",
@@ -1042,24 +1107,25 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
options ? ";" : "",
options ? options : "",
(u->user || u->password || options) ? "@": "",
- u->host,
+ allochost ? allochost : u->host,
port ? ":": "",
port ? port : "",
(u->path && (u->path[0] != '/')) ? "/": "",
u->path ? u->path : "/",
- u->query? "?": "",
- u->query? u->query : "",
+ (u->query && u->query[0]) ? "?": "",
+ (u->query && u->query[0]) ? u->query : "",
u->fragment? "#": "",
u->fragment? u->fragment : "");
+ free(allochost);
}
if(!url)
return CURLUE_OUT_OF_MEMORY;
*part = url;
return CURLUE_OK;
- break;
}
default:
ptr = NULL;
+ break;
}
if(ptr) {
*part = strdup(ptr);
@@ -1099,6 +1165,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
bool plusencode = FALSE;
bool urlskipslash = FALSE;
bool appendquery = FALSE;
+ bool equalsencode = FALSE;
if(!u)
return CURLUE_BAD_HANDLE;
@@ -1122,7 +1189,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_HOST:
storep = &u->host;
break;
+ case CURLUPART_ZONEID:
+ storep = &u->zoneid;
+ break;
case CURLUPART_PORT:
+ u->portnum = 0;
storep = &u->port;
break;
case CURLUPART_PATH:
@@ -1146,6 +1217,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
switch(what) {
case CURLUPART_SCHEME:
+ if(strlen(part) > MAX_SCHEME_LEN)
+ /* too long */
+ return CURLUE_MALFORMED_INPUT;
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
/* verify that it is a fine scheme */
!Curl_builtin_scheme(part))
@@ -1164,14 +1238,25 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_HOST:
storep = &u->host;
+ free(u->zoneid);
+ u->zoneid = NULL;
+ break;
+ case CURLUPART_ZONEID:
+ storep = &u->zoneid;
break;
case CURLUPART_PORT:
+ {
+ char *endp;
urlencode = FALSE; /* never */
- port = strtol(part, NULL, 10); /* Port number must be decimal */
+ port = strtol(part, &endp, 10); /* Port number must be decimal */
if((port <= 0) || (port > 0xffff))
return CURLUE_BAD_PORT_NUMBER;
+ if(*endp)
+ /* weirdly provided number, not good! */
+ return CURLUE_MALFORMED_INPUT;
storep = &u->port;
- break;
+ }
+ break;
case CURLUPART_PATH:
urlskipslash = TRUE;
storep = &u->path;
@@ -1179,6 +1264,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_QUERY:
plusencode = urlencode;
appendquery = (flags & CURLU_APPENDQUERY)?1:0;
+ equalsencode = appendquery;
storep = &u->query;
break;
case CURLUPART_FRAGMENT:
@@ -1196,7 +1282,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
char *redired_url;
CURLU *handle2;
- if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) {
+ if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN + 1)) {
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
@@ -1223,7 +1309,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
/* apply the relative part to create a new URL */
- redired_url = Curl_concat_url(oldurl, part);
+ redired_url = concat_url(oldurl, part);
free(oldurl);
if(!redired_url)
return CURLUE_OUT_OF_MEMORY;
@@ -1249,8 +1335,12 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *newp = part;
size_t nalloc = strlen(part);
+ if(nalloc > CURL_MAX_INPUT_LENGTH)
+ /* excessive input length */
+ return CURLUE_MALFORMED_INPUT;
+
if(urlencode) {
- const char *i;
+ const unsigned char *i;
char *o;
bool free_part = FALSE;
char *enc = malloc(nalloc * 3 + 1); /* for worst case! */
@@ -1258,7 +1348,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_OUT_OF_MEMORY;
if(plusencode) {
/* space to plus */
- i = part;
+ i = (const unsigned char *)part;
for(o = enc; *i; ++o, ++i)
*o = (*i == ' ') ? '+' : *i;
*o = 0; /* zero terminate */
@@ -1269,16 +1359,19 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
free_part = TRUE;
}
- for(i = part, o = enc; *i; i++) {
+ for(i = (const unsigned char *)part, o = enc; *i; i++) {
if(Curl_isunreserved(*i) ||
((*i == '/') && urlskipslash) ||
- ((*i == '=') && appendquery) ||
+ ((*i == '=') && equalsencode) ||
((*i == '+') && plusencode)) {
+ if((*i == '=') && equalsencode)
+ /* only skip the first equals sign */
+ equalsencode = FALSE;
*o = *i;
o++;
}
else {
- snprintf(o, 4, "%%%02x", *i);
+ msnprintf(o, 4, "%%%02x", *i);
o += 3;
}
}
@@ -1329,6 +1422,13 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
}
+ if(what == CURLUPART_HOST) {
+ if(hostname_check(u, (char *)newp)) {
+ free((char *)newp);
+ return CURLUE_MALFORMED_INPUT;
+ }
+ }
+
free(*storep);
*storep = (char *)newp;
}
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 11a6a22c6..d759592d9 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -77,7 +77,11 @@
/* Default FTP/IMAP etc response timeout in milliseconds.
Symbian OS panics when given a timeout much greater than 1/2 hour.
*/
-#define RESP_TIMEOUT (1800*1000)
+#define RESP_TIMEOUT (120*1000)
+
+/* Max string intput length is a precaution against abuse and to detect junk
+ input easier and better. */
+#define CURL_MAX_INPUT_LENGTH 8000000
#include "cookie.h"
#include "psl.h"
@@ -129,12 +133,14 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#ifdef HAVE_GSSAPI
# ifdef HAVE_GSSGNU
# include <gss.h>
-# elif defined HAVE_GSSMIT
+# elif defined HAVE_GSSAPI_GSSAPI_H
# include <gssapi/gssapi.h>
-# include <gssapi/gssapi_generic.h>
# else
# include <gssapi.h>
# endif
+# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+# include <gssapi/gssapi_generic.h>
+# endif
#endif
#ifdef HAVE_LIBSSH2_H
@@ -142,10 +148,6 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#include <libssh2_sftp.h>
#endif /* HAVE_LIBSSH2_H */
-
-/* The "master buffer" is for HTTP pipelining */
-#define MASTERBUF_SIZE 16384
-
/* Initial size of the buffer to store headers in, it'll be enlarged in case
of need. */
#define HEADERSIZE 256
@@ -154,13 +156,16 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#define GOOD_EASY_HANDLE(x) \
((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
+/* the type we use for storing a single boolean bit */
+typedef unsigned int bit;
+
#ifdef HAVE_GSSAPI
/* Types needed for krb5-ftp connections */
struct krb5buffer {
void *data;
size_t size;
size_t index;
- int eof_flag;
+ bit eof_flag:1;
};
enum protection_level {
@@ -198,21 +203,17 @@ 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. */
- bool use;
ssl_connection_state state;
ssl_connect_state connecting_state;
#if defined(USE_SSL)
struct ssl_backend_data *backend;
#endif
+ bit use:1;
};
struct ssl_primary_config {
long version; /* what version the client wants to use */
long version_max; /* max supported version the client wants to use*/
- bool verifypeer; /* set TRUE if this is desired */
- bool verifyhost; /* set TRUE if CN/SAN must match hostname */
- bool verifystatus; /* set TRUE if certificate status must be checked */
- bool sessionid; /* cache session IDs or not */
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
char *clientcert;
@@ -220,32 +221,33 @@ struct ssl_primary_config {
char *egdsocket; /* path to file containing the EGD daemon socket */
char *cipher_list; /* list of ciphers to use */
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
+ bit verifypeer:1; /* set TRUE if this is desired */
+ bit verifyhost:1; /* set TRUE if CN/SAN must match hostname */
+ bit verifystatus:1; /* set TRUE if certificate status must be checked */
+ bit sessionid:1; /* cache session IDs or not */
};
struct ssl_config_data {
struct ssl_primary_config primary;
- bool enable_beast; /* especially allow this flaw for interoperability's
- sake*/
- bool no_revoke; /* disable SSL certificate revocation checks */
long certverifyresult; /* result from the certificate verification */
char *CRLfile; /* CRL to check certificate revocation */
char *issuercert;/* optional issuer certificate filename */
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
void *fsslctxp; /* parameter for call back */
- bool certinfo; /* gather lots of certificate info */
- bool falsestart;
-
char *cert; /* client certificate file name */
char *cert_type; /* format for certificate (default: PEM)*/
char *key; /* private key file name */
char *key_type; /* format for private key (default: PEM) */
char *key_passwd; /* plain text private key password */
-
#ifdef USE_TLS_SRP
char *username; /* TLS username (for, e.g., SRP) */
char *password; /* TLS password (for, e.g., SRP) */
enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */
#endif
+ bit certinfo:1; /* gather lots of certificate info */
+ bit falsestart:1;
+ bit enable_beast:1; /* allow this flaw for interoperability's sake*/
+ bit no_revoke:1; /* disable SSL certificate revocation checks */
};
struct ssl_general_config {
@@ -284,12 +286,12 @@ struct digestdata {
char *cnonce;
char *realm;
int algo;
- bool stale; /* set true for re-negotiation */
char *opaque;
char *qop;
char *algorithm;
int nc; /* nounce count */
- bool userhash;
+ bit stale:1; /* set true for re-negotiation */
+ bit userhash:1;
#endif
};
@@ -301,6 +303,14 @@ typedef enum {
NTLMSTATE_LAST
} curlntlm;
+typedef enum {
+ GSS_AUTHNONE,
+ GSS_AUTHRECV,
+ GSS_AUTHSENT,
+ GSS_AUTHDONE,
+ GSS_AUTHSUCC
+} curlnegotiate;
+
#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
#include <iconv.h>
#endif
@@ -326,8 +336,13 @@ struct kerberos5data {
/* Struct used for NTLM challenge-response authentication */
#if defined(USE_NTLM)
struct ntlmdata {
- curlntlm state;
#ifdef USE_WINDOWS_SSPI
+/* The sslContext is used for the Schannel bindings. The
+ * api is available on the Windows 7 SDK and later.
+ */
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ CtxtHandle *sslContext;
+#endif
CredHandle *credentials;
CtxtHandle *context;
SEC_WINNT_AUTH_IDENTITY identity;
@@ -346,11 +361,9 @@ struct ntlmdata {
};
#endif
+/* Struct used for Negotiate (SPNEGO) authentication */
#ifdef USE_SPNEGO
struct negotiatedata {
- /* When doing Negotiate (SPNEGO) auth, we first need to send a token
- and then validate the received one. */
- enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state;
#ifdef HAVE_GSSAPI
OM_uint32 status;
gss_ctx_id_t context;
@@ -358,6 +371,9 @@ struct negotiatedata {
gss_buffer_desc output_token;
#else
#ifdef USE_WINDOWS_SSPI
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ CtxtHandle *sslContext;
+#endif
DWORD status;
CredHandle *credentials;
CtxtHandle *context;
@@ -369,6 +385,10 @@ struct negotiatedata {
size_t output_token_length;
#endif
#endif
+ bool noauthpersist;
+ bool havenoauthpersist;
+ bool havenegdata;
+ bool havemultiplerequests;
};
#endif
@@ -378,69 +398,67 @@ struct negotiatedata {
*/
struct ConnectBits {
/* always modify bits.close with the connclose() and connkeep() macros! */
- bool close; /* if set, we close the connection after this request */
- bool reuse; /* if set, this is a re-used connection */
- bool conn_to_host; /* if set, this connection has a "connect to host"
- that overrides the host in the URL */
- bool conn_to_port; /* if set, this connection has a "connect to port"
- that overrides the port in the URL (remote port) */
- bool proxy; /* if set, this transfer is done through a proxy - any type */
- bool httpproxy; /* if set, this transfer is done through a http proxy */
- bool socksproxy; /* if set, this transfer is done through a socks proxy */
- bool user_passwd; /* do we use user+password for this connection? */
- bool proxy_user_passwd; /* user+password for the proxy? */
- bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6
- IP address */
- bool ipv6; /* we communicate with a site using an IPv6 address */
-
- bool do_more; /* this is set TRUE if the ->curl_do_more() function is
- supposed to be called, after ->curl_do() */
- bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
- the first time on the first connect function call */
- bool protoconnstart;/* the protocol layer has STARTED its operation after
- the TCP layer connect */
-
- bool retry; /* this connection is about to get closed and then
- re-attempted at another connection. */
- bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy.
- This is implicit when SSL-protocols are used through
- proxies, but can also be enabled explicitly by
- apps */
- bool authneg; /* TRUE when the auth phase has started, which means
- that we are creating a request with an auth header,
- but it is not the final request in the auth
- negotiation. */
- bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
- though it will be discarded. When the whole send
- operation is done, we must call the data rewind
- callback. */
- bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
- EPSV doesn't work we disable it for the forthcoming
- requests */
-
- bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
- EPRT doesn't work we disable it for the forthcoming
- requests */
- bool ftp_use_data_ssl; /* Enabled SSL for the data connection */
- bool netrc; /* name+password provided by netrc */
- bool userpwd_in_url; /* name+password found in url */
- bool stream_was_rewound; /* Indicates that the stream was rewound after a
- request read past the end of its response byte
- boundary */
- bool proxy_connect_closed; /* set true if a proxy disconnected the
- connection in a CONNECT request with auth, so
- that libcurl should reconnect and continue. */
- bool bound; /* set true if bind() has already been done on this socket/
- connection */
- bool type_set; /* type= was used in the URL */
- bool multiplex; /* connection is multiplexed */
-
- bool tcp_fastopen; /* use TCP Fast Open */
- bool tls_enable_npn; /* TLS NPN extension? */
- bool tls_enable_alpn; /* TLS ALPN extension? */
bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy
is complete */
- bool socksproxy_connecting; /* connecting through a socks proxy */
+ bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
+ the first time on the first connect function call */
+ bit close:1; /* if set, we close the connection after this request */
+ bit reuse:1; /* if set, this is a re-used connection */
+ bit conn_to_host:1; /* if set, this connection has a "connect to host"
+ that overrides the host in the URL */
+ bit conn_to_port:1; /* if set, this connection has a "connect to port"
+ that overrides the port in the URL (remote port) */
+ bit proxy:1; /* if set, this transfer is done through a proxy - any type */
+ bit httpproxy:1; /* if set, this transfer is done through a http proxy */
+ bit socksproxy:1; /* if set, this transfer is done through a socks proxy */
+ bit user_passwd:1; /* do we use user+password for this connection? */
+ bit proxy_user_passwd:1; /* user+password for the proxy? */
+ bit ipv6_ip:1; /* we communicate with a remote site specified with pure IPv6
+ IP address */
+ bit ipv6:1; /* we communicate with a site using an IPv6 address */
+ bit do_more:1; /* this is set TRUE if the ->curl_do_more() function is
+ supposed to be called, after ->curl_do() */
+ bit protoconnstart:1;/* the protocol layer has STARTED its operation after
+ the TCP layer connect */
+ bit retry:1; /* this connection is about to get closed and then
+ re-attempted at another connection. */
+ bit tunnel_proxy:1; /* if CONNECT is used to "tunnel" through the proxy.
+ This is implicit when SSL-protocols are used through
+ proxies, but can also be enabled explicitly by
+ apps */
+ bit authneg:1; /* TRUE when the auth phase has started, which means
+ that we are creating a request with an auth header,
+ but it is not the final request in the auth
+ negotiation. */
+ bit rewindaftersend:1;/* TRUE when the sending couldn't be stopped even
+ though it will be discarded. When the whole send
+ operation is done, we must call the data rewind
+ callback. */
+#ifndef CURL_DISABLE_FTP
+ bit ftp_use_epsv:1; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
+ EPSV doesn't work we disable it for the forthcoming
+ requests */
+ bit ftp_use_eprt:1; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
+ EPRT doesn't work we disable it for the forthcoming
+ requests */
+ bit ftp_use_data_ssl:1; /* Enabled SSL for the data connection */
+#endif
+ bit netrc:1; /* name+password provided by netrc */
+ bit userpwd_in_url:1; /* name+password found in url */
+ bit stream_was_rewound:1; /* The stream was rewound after a request read
+ past the end of its response byte boundary */
+ bit proxy_connect_closed:1; /* TRUE if a proxy disconnected the connection
+ in a CONNECT request with auth, so that
+ libcurl should reconnect and continue. */
+ bit bound:1; /* set true if bind() has already been done on this socket/
+ connection */
+ bit type_set:1; /* type= was used in the URL */
+ bit multiplex:1; /* connection is multiplexed */
+ bit tcp_fastopen:1; /* use TCP Fast Open */
+ bit tls_enable_npn:1; /* TLS NPN extension? */
+ bit tls_enable_alpn:1; /* TLS ALPN extension? */
+ bit socksproxy_connecting:1; /* connecting through a socks proxy */
+ bit connect_only:1;
};
struct hostname {
@@ -467,14 +485,13 @@ struct hostname {
#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
-
struct Curl_async {
char *hostname;
int port;
struct Curl_dns_entry *dns;
- bool done; /* set TRUE when the lookup is complete */
int status; /* if done is TRUE, this is the status from the callback */
void *os_specific; /* 'struct thread_data' for Windows */
+ bit done:1; /* set TRUE when the lookup is complete */
};
#define FIRSTSOCKET 0
@@ -532,25 +549,21 @@ struct dohdata {
*/
struct SingleRequest {
curl_off_t size; /* -1 if unknown at this point */
- curl_off_t *bytecountp; /* return number of bytes read or NULL */
-
curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
-1 means unlimited */
- curl_off_t *writebytecountp; /* return number of bytes written or NULL */
-
curl_off_t bytecount; /* total number of bytes read */
curl_off_t writebytecount; /* number of bytes written */
- long headerbytecount; /* only count received headers */
- long deductheadercount; /* this amount of bytes doesn't count when we check
- if anything has been transferred at the end of a
- connection. We use this counter to make only a
- 100 reply (without a following second response
- code) result in a CURLE_GOT_NOTHING error code */
+ curl_off_t headerbytecount; /* only count received headers */
+ curl_off_t deductheadercount; /* this amount of bytes doesn't count when we
+ check if anything has been transferred at
+ the end of a connection. We use this
+ counter to make only a 100 reply (without a
+ following second response code) result in a
+ CURLE_GOT_NOTHING error code */
struct curltime start; /* transfer started at this time */
struct curltime now; /* current time */
- bool header; /* incoming data has HTTP header */
enum {
HEADER_NORMAL, /* no bad header at all */
HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
@@ -566,7 +579,6 @@ struct SingleRequest {
char *str_start; /* within buf */
char *end_ptr; /* within buf */
char *p; /* within headerbuff */
- bool content_range; /* set TRUE if Content-Range: was found */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
@@ -579,19 +591,8 @@ struct SingleRequest {
/* See sec 3.5, RFC2616. */
time_t timeofdoc;
long bodywrites;
-
char *buf;
- curl_socket_t maxfd;
-
int keepon;
-
- bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
- and we're uploading the last chunk */
-
- bool ignorebody; /* we read a response-body but we ignore it! */
- bool ignorecl; /* This HTTP response has no body so we ignore the Content-
- Length: header */
-
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
@@ -601,24 +602,30 @@ struct SingleRequest {
still left in the buffer, aimed for upload. */
ssize_t upload_present;
- /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
- buffer, so the next read should read from where this pointer points to,
- and the 'upload_present' contains the number of bytes available at this
- position */
+ /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+ buffer, so the next read should read from where this pointer points to,
+ and the 'upload_present' contains the number of bytes available at this
+ position */
char *upload_fromhere;
-
- bool chunk; /* if set, this is a chunked transfer-encoding */
- bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
- on upload */
- bool getheader; /* TRUE if header parsing is wanted */
-
- bool forbidchunk; /* used only to explicitly forbid chunk-upload for
- specific upload buffers. See readmoredata() in
- http.c for details. */
-
void *protop; /* Allocated protocol-specific data. Each protocol
handler makes sure this points to data it needs. */
+#ifndef CURL_DISABLE_DOH
struct dohdata doh; /* DoH specific data for this request */
+#endif
+ bit header:1; /* incoming data has HTTP header */
+ bit content_range:1; /* set TRUE if Content-Range: was found */
+ bit upload_done:1; /* set to TRUE when doing chunked transfer-encoding
+ upload and we're uploading the last chunk */
+ bit ignorebody:1; /* we read a response-body but we ignore it! */
+ bit ignorecl:1; /* This HTTP response has no body so we ignore the
+ Content-Length: header */
+ bit chunk:1; /* if set, this is a chunked transfer-encoding */
+ bit upload_chunky:1; /* set TRUE if we are doing chunked transfer-encoding
+ on upload */
+ bit getheader:1; /* TRUE if header parsing is wanted */
+ bit forbidchunk:1; /* used only to explicitly forbid chunk-upload for
+ specific upload buffers. See readmoredata() in http.c
+ for details. */
};
/*
@@ -766,13 +773,13 @@ struct http_connect_state {
char *line_start;
char *ptr; /* where to store more data */
curl_off_t cl; /* size of content to read and ignore */
- bool chunked_encoding;
enum {
TUNNEL_INIT, /* init/default/no tunnel state */
TUNNEL_CONNECT, /* CONNECT has been sent off */
TUNNEL_COMPLETE /* CONNECT response received completely */
} tunnel_state;
- bool close_connection;
+ bit chunked_encoding:1;
+ bit close_connection:1;
};
/*
@@ -796,11 +803,10 @@ struct connectdata {
void *closesocket_client;
/* This is used by the connection cache logic. If this returns TRUE, this
- handle is being used by one or more easy handles and can only used by any
+ handle is still used by one or more easy handles and can only used by any
other easy handle without careful consideration (== only for
- pipelining/multiplexing) and it cannot be used by another multi
- handle! */
-#define CONN_INUSE(c) ((c)->send_pipe.size + (c)->recv_pipe.size)
+ multiplexing) and it cannot be used by another multi handle! */
+#define CONN_INUSE(c) ((c)->easyq.size)
/**** Fields set when inited and not modified again */
long connection_id; /* Contains a unique number to make it easier to
@@ -828,6 +834,7 @@ struct connectdata {
int socktype; /* SOCK_STREAM or SOCK_DGRAM */
struct hostname host;
+ char *hostname_resolve; /* host name to resolve to address, allocated */
char *secondaryhostname; /* secondary socket host name (ftp) */
struct hostname conn_to_host; /* the host to connect to. valid only if
bits.conn_to_host is set */
@@ -870,6 +877,7 @@ struct connectdata {
struct curltime now; /* "current" time */
struct curltime created; /* creation time */
+ struct curltime lastused; /* when returned to the connection cache */
curl_socket_t sock[2]; /* two sockets, the second is used for the data
transfer when doing FTP */
curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */
@@ -888,8 +896,6 @@ struct connectdata {
#endif
struct ssl_primary_config ssl_config;
struct ssl_primary_config proxy_ssl_config;
- bool tls_upgraded;
-
struct ConnectBits bits; /* various state-flags for this connection */
/* connecttime: when connect() is called on the current IP address. Used to
@@ -936,7 +942,7 @@ struct connectdata {
} allocptr;
#ifdef HAVE_GSSAPI
- int sec_complete; /* if Kerberos is enabled for this connection */
+ bit sec_complete:1; /* if Kerberos is enabled for this connection */
enum protection_level command_prot;
enum protection_level data_prot;
enum protection_level request_data_prot;
@@ -951,30 +957,19 @@ struct connectdata {
struct kerberos5data krb5; /* variables into the structure definition, */
#endif /* however, some of them are ftp specific. */
- /* the two following *_inuse fields are only flags, not counters in any way.
- If TRUE it means the channel is in use, and if FALSE it means the channel
- is up for grabs by one. */
-
- bool readchannel_inuse; /* whether the read channel is in use by an easy
- handle */
- bool writechannel_inuse; /* whether the write channel is in use by an easy
- handle */
- struct curl_llist send_pipe; /* List of handles waiting to send on this
- pipeline */
- struct curl_llist recv_pipe; /* List of handles waiting to read their
- responses on this pipeline */
- char *master_buffer; /* The master buffer allocated on-demand;
- used for pipelining. */
- size_t read_pos; /* Current read position in the master buffer */
- size_t buf_len; /* Length of the buffer?? */
-
-
+ 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 */
/*************** Request - specific items ************/
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+ CtxtHandle *sslContext;
+#endif
#if defined(USE_NTLM)
+ curlntlm http_ntlm_state;
+ curlntlm proxy_ntlm_state;
+
struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
because it authenticates connections, not
single requests! */
@@ -989,7 +984,14 @@ struct connectdata {
#endif
#endif
- char syserr_buf [256]; /* buffer for Curl_strerror() */
+#ifdef USE_SPNEGO
+ curlnegotiate http_negotiate_state;
+ curlnegotiate proxy_negotiate_state;
+
+ struct negotiatedata negotiate; /* state data for host Negotiate auth */
+ struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
+#endif
+
/* data used for the asynch name resolve callback */
struct Curl_async async;
@@ -1032,8 +1034,16 @@ struct connectdata {
#ifdef USE_UNIX_SOCKETS
char *unix_domain_socket;
- bool abstract_unix_socket;
+ bit abstract_unix_socket:1;
#endif
+ bit tls_upgraded:1;
+ /* the two following *_inuse fields are only flags, not counters in any way.
+ If TRUE it means the channel is in use, and if FALSE it means the channel
+ is up for grabs by one. */
+ bit readchannel_inuse:1; /* whether the read channel is in use by an easy
+ handle */
+ bit writechannel_inuse:1; /* whether the write channel is in use by an easy
+ handle */
};
/* The end of connectdata. */
@@ -1048,10 +1058,8 @@ struct PureInfo {
int httpversion; /* the http version number X.Y = X*10+Y */
time_t filetime; /* If requested, this is might get set. Set to -1 if the
time was unretrievable. */
- bool timecond; /* set to TRUE if the time condition didn't match, which
- thus made the document NOT get fetched */
- long header_size; /* size of read header(s) in bytes */
- long request_size; /* the amount of bytes sent in the request(s) */
+ curl_off_t header_size; /* size of read header(s) in bytes */
+ curl_off_t request_size; /* the amount of bytes sent in the request(s) */
unsigned long proxyauthavail; /* what proxy auth types were announced */
unsigned long httpauthavail; /* what host auth types were announced */
long numconnects; /* how many new connection did libcurl created */
@@ -1068,16 +1076,16 @@ struct PureInfo {
char conn_primary_ip[MAX_IPADR_LEN];
long conn_primary_port;
-
char conn_local_ip[MAX_IPADR_LEN];
long conn_local_port;
-
const char *conn_scheme;
unsigned int conn_protocol;
-
struct curl_certinfo certs; /* info about the certs, only populated in
OpenSSL builds. Asked for with
CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+
+ bit timecond:1; /* set to TRUE if the time condition didn't match, which
+ thus made the document NOT get fetched */
};
@@ -1091,7 +1099,6 @@ struct Progress {
curl_off_t current_speed; /* uses the currently fastest transfer */
- bool callback; /* set when progress callback is used */
int width; /* screen width at download start */
int flags; /* see progress.h */
@@ -1112,7 +1119,6 @@ struct Progress {
struct curltime t_startop;
struct curltime t_acceptdata;
- bool is_t_startransfer_set;
/* upload speed limit */
struct curltime ul_limit_start;
@@ -1126,6 +1132,8 @@ struct Progress {
curl_off_t speeder[ CURR_TIME ];
struct curltime speeder_time[ CURR_TIME ];
int speeder_c;
+ bit callback:1; /* set when progress callback is used */
+ bit is_t_startransfer_set:1;
};
typedef enum {
@@ -1137,7 +1145,6 @@ typedef enum {
HTTPREQ_PUT,
HTTPREQ_HEAD,
HTTPREQ_OPTIONS,
- HTTPREQ_CUSTOM,
HTTPREQ_LAST /* last in list */
} Curl_HttpReq;
@@ -1174,12 +1181,12 @@ struct auth {
unsigned long picked;
unsigned long avail; /* Bitmask for what the server reports to support for
this resource */
- bool done; /* TRUE when the auth phase is done and ready to do the *actual*
- request */
- bool multipass; /* TRUE if this is not yet authenticated but within the
- auth multipass negotiation */
- bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should
- be RFC compliant */
+ bit done:1; /* TRUE when the auth phase is done and ready to do the
+ *actual* request */
+ bit multipass:1; /* TRUE if this is not yet authenticated but within the
+ auth multipass negotiation */
+ bit iestyle:1; /* TRUE if digest should be done IE-style or FALSE if it
+ should be RFC compliant */
};
struct Curl_http2_dep {
@@ -1206,6 +1213,7 @@ typedef enum {
EXPIRE_ASYNC_NAME,
EXPIRE_CONNECTTIMEOUT,
EXPIRE_DNS_PER_NAME,
+ EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */
EXPIRE_HAPPY_EYEBALLS,
EXPIRE_MULTI_PENDING,
EXPIRE_RUN_NOW,
@@ -1215,6 +1223,15 @@ typedef enum {
EXPIRE_LAST /* not an actual timer, used as a marker only */
} expire_id;
+
+typedef enum {
+ TRAILERS_NONE,
+ TRAILERS_INITIALIZED,
+ TRAILERS_SENDING,
+ TRAILERS_DONE
+} trailers_state;
+
+
/*
* One instance for each timeout an easy handle can set.
*/
@@ -1241,11 +1258,6 @@ struct UrlState {
/* Points to the connection cache */
struct conncache *conn_cache;
- /* when curl_easy_perform() is called, the multi handle is "owned" by
- the easy handle so curl_easy_cleanup() on such an easy handle will
- also close the multi handle! */
- bool multi_owned_by_easy;
-
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
@@ -1258,8 +1270,6 @@ struct UrlState {
char *ulbuf; /* allocated upload buffer or NULL */
curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */
- bool this_is_a_follow; /* this is a followed Location: request */
- bool refused_stream; /* this was refused, try again */
char *first_host; /* host name of the first (not followed) request.
if set, this should be the host name that we will
sent authorization to, no else. Used to make Location:
@@ -1272,29 +1282,16 @@ struct UrlState {
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 */
- bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
- This must be set to FALSE every time _easy_perform() is
- called. */
int os_errno; /* filled in with errno whenever an error occurs */
#ifdef HAVE_SIGNAL
/* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
void (*prev_signal)(int sig);
#endif
- bool allow_port; /* Is set.use_port allowed to take effect or not. This
- is always set TRUE when curl_easy_perform() is called. */
struct digestdata digest; /* state data for host Digest auth */
struct digestdata proxydigest; /* state data for proxy Digest auth */
-#ifdef USE_SPNEGO
- struct negotiatedata negotiate; /* state data for host Negotiate auth */
- struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
-#endif
-
struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */
-
- bool authproblem; /* TRUE if there's some problem authenticating */
-
void *resolver; /* resolver state, if it is used in the URL state -
ares_channel f.e. */
@@ -1310,27 +1307,18 @@ struct UrlState {
/* a place to store the most recently set FTP entrypath */
char *most_recent_ftp_entrypath;
- /* set after initial USER failure, to prevent an authentication loop */
- bool ftp_trying_alternative;
- bool wildcardmatch; /* enable wildcard matching */
int httpversion; /* the lowest HTTP version*10 reported by any server
involved in this request */
- bool expect100header; /* TRUE if we added Expect: 100-continue */
#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \
!defined(__SYMBIAN32__)
/* do FTP line-end conversions on most platforms */
#define CURL_DO_LINEEND_CONV
/* for FTP downloads: track CRLF sequences that span blocks */
- bool prev_block_had_trailing_cr;
+ bit prev_block_had_trailing_cr:1;
/* for FTP downloads: how many CRLFs did we converted to LFs? */
curl_off_t crlf_conversions;
#endif
- bool slash_removed; /* set TRUE if the 'path' points to a path where the
- initial URL slash separator has been taken off */
- bool use_range;
- bool rangestringalloc; /* the range string is malloc()'ed */
-
char *range; /* range, if used. See README for detailed specification on
this syntax. */
curl_off_t resume_from; /* continue [ftp] transfer from here */
@@ -1346,21 +1334,48 @@ struct UrlState {
size_t drain; /* Increased when this stream has data to read, even if its
socket is not necessarily is readable. Decreased when
checked. */
- bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE
- when multi_done() is called, to prevent multi_done() to get
- invoked twice when the multi interface is used. */
curl_read_callback fread_func; /* read callback/function */
void *in; /* CURLOPT_READDATA */
struct Curl_easy *stream_depends_on;
- bool stream_depends_e; /* set or don't set the Exclusive bit */
int stream_weight;
-#ifdef CURLDEBUG
- bool conncache_lock;
-#endif
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
+#ifndef CURL_DISABLE_HTTP
+ size_t trailers_bytes_sent;
+ Curl_send_buffer *trailers_buf; /* a buffer containing the compiled trailing
+ headers */
+#endif
+ trailers_state trailers_state; /* whether we are sending trailers
+ and what stage are we at */
+#ifdef CURLDEBUG
+ bit conncache_lock:1;
+#endif
+ /* when curl_easy_perform() is called, the multi handle is "owned" by
+ the easy handle so curl_easy_cleanup() on such an easy handle will
+ also close the multi handle! */
+ bit multi_owned_by_easy:1;
+
+ bit this_is_a_follow:1; /* this is a followed Location: request */
+ bit refused_stream:1; /* this was refused, try again */
+ bit errorbuf:1; /* Set to TRUE if the error buffer is already filled in.
+ This must be set to FALSE every time _easy_perform() is
+ called. */
+ bit allow_port:1; /* Is set.use_port allowed to take effect or not. This
+ is always set TRUE when curl_easy_perform() is called. */
+ bit authproblem:1; /* TRUE if there's some problem authenticating */
+ /* set after initial USER failure, to prevent an authentication loop */
+ bit ftp_trying_alternative:1;
+ bit wildcardmatch:1; /* enable wildcard matching */
+ bit expect100header:1; /* TRUE if we added Expect: 100-continue */
+ bit use_range:1;
+ bit rangestringalloc:1; /* the range string is malloc()'ed */
+ bit done:1; /* set to FALSE when Curl_init_do() is called and set to TRUE
+ when multi_done() is called, to prevent multi_done() to get
+ invoked twice when the multi interface is used. */
+ bit stream_depends_e:1; /* set or don't set the Exclusive bit */
+ bit previouslypending:1; /* this transfer WAS in the multi->pending queue */
};
@@ -1373,13 +1388,15 @@ struct UrlState {
struct DynamicStatic {
char *url; /* work URL, copied from UserDefined */
- bool url_alloc; /* URL string is malloc()'ed */
char *referer; /* referer string */
- bool referer_alloc; /* referer string is malloc()ed */
struct curl_slist *cookielist; /* list of cookie files set by
curl_easy_setopt(COOKIEFILE) calls */
struct curl_slist *resolve; /* set to point to the set.resolve list when
this should be dealt with in pretransfer */
+ bit url_alloc:1; /* URL string is malloc()'ed */
+ bit referer_alloc:1; /* referer string is malloc()ed */
+ bit wildcard_resolve:1; /* Set to true if any resolve change is a
+ wildcard */
};
/*
@@ -1449,7 +1466,7 @@ 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 */
-#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
+#ifdef USE_SSH
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 */
@@ -1472,6 +1489,9 @@ enum dupstring {
#endif
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
STRING_DOH, /* CURLOPT_DOH_URL */
+#ifdef USE_ALTSVC
+ STRING_ALTSVC, /* CURLOPT_ALTSVC */
+#endif
/* -- end of zero-terminated strings -- */
STRING_LASTZEROTERMINATED,
@@ -1509,8 +1529,6 @@ struct UserDefined {
int keep_post; /* keep POSTs as POSTs after a 30x request; each
bit represents a request, from 301 to 303 */
- bool free_referer; /* set TRUE if 'referer' points to a string we
- allocated */
void *postfields; /* if POST, set the fields' values here */
curl_seek_callback seek_func; /* function that seeks the input */
curl_off_t postfieldsize; /* if POST, this might have a size to use instead
@@ -1523,8 +1541,6 @@ struct UserDefined {
curl_write_callback fwrite_header; /* function that stores headers */
curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */
curl_read_callback fread_func_set; /* function that reads the input */
- int is_fread_set; /* boolean, has read callback been set to non-NULL? */
- int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
curl_progress_callback fprogress; /* OLD and deprecated progress callback */
curl_xferinfo_callback fxferinfo; /* progress callback */
curl_debug_callback fdebug; /* function that write informational data */
@@ -1555,8 +1571,9 @@ struct UserDefined {
long accepttimeout; /* in milliseconds, 0 means no timeout */
long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */
long server_response_timeout; /* in milliseconds, 0 means no timeout */
+ long maxage_conn; /* in seconds, max idle time to allow a connection that
+ is to be reused */
long tftp_blksize; /* in bytes, 0 means use default */
- bool tftp_no_options; /* do not send TFTP options requests */
curl_off_t filesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */
long low_speed_time; /* number of seconds */
@@ -1568,9 +1585,6 @@ struct UserDefined {
struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
struct curl_httppost *httppost; /* linked list of old POST data */
curl_mimepart mimepost; /* MIME/POST data. */
- bool sep_headers; /* handle host and proxy headers separately */
- bool cookiesession; /* new cookie session? */
- bool crlf; /* convert crlf on ftp upload(?) */
struct curl_slist *quote; /* after connection is established */
struct curl_slist *postquote; /* after the transfer */
struct curl_slist *prequote; /* before the transfer, after type */
@@ -1589,7 +1603,6 @@ struct UserDefined {
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
long httpversion; /* when non-zero, a specific HTTP version requested to
be used in the library's request(s) */
- bool strip_path_slash; /* strip off initial slash from path */
struct ssl_config_data ssl; /* user defined SSL stuff */
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */
struct ssl_general_config general_ssl; /* general user defined SSL stuff */
@@ -1599,87 +1612,35 @@ struct UserDefined {
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 */
-
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 */
-
+ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
+ curl_ftpccc ftp_ccc; /* FTP CCC options */
+#endif
int ftp_create_missing_dirs; /* 1 - create directories that don't exist
2 - the same but also allow MKD to fail once
*/
-
curl_sshkeycallback ssh_keyfunc; /* key matching callback */
void *ssh_keyfunc_userp; /* custom pointer to callback */
- bool ssh_compression; /* enable SSH compression */
-
-/* Here follows boolean settings that define how to behave during
- this session. They are STATIC, set by libcurl users or at least initially
- and they don't change during operations. */
- bool get_filetime; /* get the time and get of the remote file */
- bool tunnel_thru_httpproxy; /* use CONNECT through a HTTP proxy */
- bool prefer_ascii; /* ASCII rather than binary */
- bool ftp_append; /* append, not overwrite, on upload */
- bool ftp_list_only; /* switch FTP command for listing directories */
- bool ftp_use_port; /* use the FTP PORT command */
- bool hide_progress; /* don't use the progress meter */
- bool http_fail_on_error; /* fail on HTTP error codes >= 400 */
- bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */
- bool http_follow_location; /* follow HTTP redirects */
- bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */
- bool allow_auth_to_other_hosts;
- bool include_header; /* include received protocol headers in data output */
- bool http_set_referer; /* is a custom referer used */
- bool http_auto_referer; /* set "correct" referer when following location: */
- bool opt_no_body; /* as set with CURLOPT_NOBODY */
- bool upload; /* upload request */
enum CURL_NETRC_OPTION
use_netrc; /* defined in include/curl.h */
- bool verbose; /* output verbosity */
- bool krb; /* Kerberos connection requested */
- bool reuse_forbid; /* forbidden to be reused, close after use */
- bool reuse_fresh; /* do not re-use an existing connection */
- bool ftp_use_epsv; /* if EPSV is to be attempted or not */
- bool ftp_use_eprt; /* if EPRT is to be attempted or not */
- bool ftp_use_pret; /* if PRET is to be used before PASV or not */
-
curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
IMAP or POP3 or others! */
- curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
- curl_ftpccc ftp_ccc; /* FTP CCC options */
- bool no_signal; /* do not use any signal/alarm handler */
- bool global_dns_cache; /* subject for future removal */
- bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */
- bool ignorecl; /* ignore content length */
- bool ftp_skip_ip; /* skip the IP address the FTP server passes on to
- us */
- bool connect_only; /* make connection, let application use the socket */
- long ssh_auth_types; /* allowed SSH auth types */
- bool http_te_skip; /* pass the raw body data to the user, even when
- transfer-encoded (chunked, compressed) */
- bool http_ce_skip; /* pass the raw body data to the user, even when
- content-encoded (chunked, compressed) */
long new_file_perms; /* Permissions to use when creating remote files */
long new_directory_perms; /* Permissions to use when creating remote dirs */
- bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP
- via an HTTP proxy */
+ long ssh_auth_types; /* allowed SSH auth types */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
unsigned int scope_id; /* Scope id for IPv6 */
long allowed_protocols;
long redir_protocols;
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */
-#endif
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
- bool sasl_ir; /* Enable/disable SASL initial response */
/* Common RTSP header options */
Curl_RtspReq rtspreq; /* RTSP request type */
long rtspversion; /* like httpversion, for RTSP */
- bool wildcard_enabled; /* enable wildcard matching */
curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
starts */
curl_chunk_end_callback chunk_end; /* called after part transferring
@@ -1691,50 +1652,109 @@ struct UserDefined {
long gssapi_delegation; /* GSS-API credential delegation, see the
documentation of CURLOPT_GSSAPI_DELEGATION */
- bool tcp_keepalive; /* use TCP keepalives */
long tcp_keepidle; /* seconds in idle before sending keepalive probe */
long tcp_keepintvl; /* seconds between TCP keepalive probes */
- bool tcp_fastopen; /* use TCP Fast Open */
- size_t maxconnects; /* Max idle connections in the connection cache */
+ size_t maxconnects; /* Max idle connections in the connection cache */
- bool ssl_enable_npn; /* TLS NPN extension? */
- bool ssl_enable_alpn; /* TLS ALPN extension? */
- bool path_as_is; /* allow dotdots? */
- bool pipewait; /* wait for pipe/multiplex status before starting a
- new connection */
long expect_100_timeout; /* in milliseconds */
- bool suppress_connect_headers; /* suppress proxy CONNECT response headers
- from user callbacks */
-
- bool dns_shuffle_addresses; /* whether to shuffle addresses before use */
-
struct Curl_easy *stream_depends_on;
- bool stream_depends_e; /* set or don't set the Exclusive bit */
int stream_weight;
-
- bool haproxyprotocol; /* whether to send HAProxy PROXY protocol v1 header */
-
struct Curl_http2_dep *stream_dependents;
- bool abstract_unix_socket;
-
curl_resolver_start_callback resolver_start; /* optional callback called
before resolver start */
void *resolver_start_client; /* pointer to pass to resolver start callback */
- bool disallow_username_in_url; /* disallow username in url */
long upkeep_interval_ms; /* Time between calls for connection upkeep. */
- bool doh; /* DNS-over-HTTPS enabled */
- bool doh_get; /* use GET for DoH requests, instead of POST */
multidone_func fmultidone;
struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
+ CURLU *uh; /* URL handle for the current parsed URL */
+ void *trailer_data; /* pointer to pass to trailer data callback */
+ curl_trailer_callback trailer_callback; /* trailing data callback */
+ bit is_fread_set:1; /* has read callback been set to non-NULL? */
+ bit is_fwrite_set:1; /* has write callback been set to non-NULL? */
+ bit free_referer:1; /* set TRUE if 'referer' points to a string we
+ allocated */
+ bit tftp_no_options:1; /* do not send TFTP options requests */
+ bit sep_headers:1; /* handle host and proxy headers separately */
+ bit cookiesession:1; /* new cookie session? */
+ bit crlf:1; /* convert crlf on ftp upload(?) */
+ bit strip_path_slash:1; /* strip off initial slash from path */
+ bit ssh_compression:1; /* enable SSH compression */
+
+/* Here follows boolean settings that define how to behave during
+ this session. They are STATIC, set by libcurl users or at least initially
+ and they don't change during operations. */
+ bit get_filetime:1; /* get the time and get of the remote file */
+ bit tunnel_thru_httpproxy:1; /* use CONNECT through a HTTP proxy */
+ bit prefer_ascii:1; /* ASCII rather than binary */
+ bit ftp_append:1; /* append, not overwrite, on upload */
+ bit ftp_list_only:1; /* switch FTP command for listing directories */
+#ifndef CURL_DISABLE_FTP
+ bit ftp_use_port:1; /* use the FTP PORT command */
+ bit ftp_use_epsv:1; /* if EPSV is to be attempted or not */
+ bit ftp_use_eprt:1; /* if EPRT is to be attempted or not */
+ bit ftp_use_pret:1; /* if PRET is to be used before PASV or not */
+ bit ftp_skip_ip:1; /* skip the IP address the FTP server passes on to
+ us */
+#endif
+ bit hide_progress:1; /* don't use the progress meter */
+ bit http_fail_on_error:1; /* fail on HTTP error codes >= 400 */
+ bit http_keep_sending_on_error:1; /* for HTTP status codes >= 300 */
+ bit http_follow_location:1; /* follow HTTP redirects */
+ bit http_transfer_encoding:1; /* request compressed HTTP
+ transfer-encoding */
+ bit allow_auth_to_other_hosts:1;
+ bit include_header:1; /* include received protocol headers in data output */
+ bit http_set_referer:1; /* is a custom referer used */
+ bit http_auto_referer:1; /* set "correct" referer when following
+ location: */
+ bit opt_no_body:1; /* as set with CURLOPT_NOBODY */
+ bit upload:1; /* upload request */
+ bit verbose:1; /* output verbosity */
+ bit krb:1; /* Kerberos connection requested */
+ bit reuse_forbid:1; /* forbidden to be reused, close after use */
+ bit reuse_fresh:1; /* do not re-use an existing connection */
+
+ bit no_signal:1; /* do not use any signal/alarm handler */
+ bit tcp_nodelay:1; /* whether to enable TCP_NODELAY or not */
+ bit ignorecl:1; /* ignore content length */
+ bit connect_only:1; /* make connection, let application use the socket */
+ bit http_te_skip:1; /* pass the raw body data to the user, even when
+ transfer-encoded (chunked, compressed) */
+ bit http_ce_skip:1; /* pass the raw body data to the user, even when
+ content-encoded (chunked, compressed) */
+ bit proxy_transfer_mode:1; /* set transfer mode (;type=<a|i>) when doing
+ FTP via an HTTP proxy */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ bit socks5_gssapi_nec:1; /* Flag to support NEC SOCKS5 server */
+#endif
+ bit sasl_ir:1; /* Enable/disable SASL initial response */
+ bit wildcard_enabled:1; /* enable wildcard matching */
+ bit tcp_keepalive:1; /* use TCP keepalives */
+ bit tcp_fastopen:1; /* use TCP Fast Open */
+ bit ssl_enable_npn:1; /* TLS NPN extension? */
+ bit ssl_enable_alpn:1;/* TLS ALPN extension? */
+ bit path_as_is:1; /* allow dotdots? */
+ bit pipewait:1; /* wait for multiplex status before starting a new
+ connection */
+ bit suppress_connect_headers:1; /* suppress proxy CONNECT response headers
+ from user callbacks */
+ bit dns_shuffle_addresses:1; /* whether to shuffle addresses before use */
+ bit stream_depends_e:1; /* set or don't set the Exclusive bit */
+ bit haproxyprotocol:1; /* whether to send HAProxy PROXY protocol v1
+ header */
+ bit abstract_unix_socket:1;
+ bit disallow_username_in_url:1; /* disallow username in url */
+ bit doh:1; /* DNS-over-HTTPS enabled */
+ bit doh_get:1; /* use GET for DoH requests, instead of POST */
+ bit http09_allowed:1; /* allow HTTP/0.9 responses */
};
struct Names {
struct curl_hash *hostcache;
enum {
HCACHE_NONE, /* not pointing to anything */
- HCACHE_GLOBAL, /* points to the (shrug) global one */
HCACHE_MULTI, /* points to a shared one in the multi handle */
HCACHE_SHARED /* points to a shared one in a shared object */
} hostcachetype;
@@ -1755,9 +1775,10 @@ struct Curl_easy {
struct Curl_easy *next;
struct Curl_easy *prev;
- struct connectdata *easy_conn; /* the "unit's" connection */
+ struct connectdata *conn;
struct curl_llist_element connect_queue;
- struct curl_llist_element pipeline_queue;
+ struct curl_llist_element sh_queue; /* list per Curl_sh_entry */
+ struct curl_llist_element conn_queue; /* list per connectdata */
CURLMstate mstate; /* the handle's state */
CURLcode result; /* previous result */
@@ -1769,6 +1790,8 @@ struct Curl_easy {
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+ int actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in
+ sockets[] */
int numsocks;
struct Names dns;
@@ -1789,10 +1812,15 @@ 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
+ struct altsvcinfo *asi; /* the alt-svc cache */
+#endif
struct Progress progress; /* for all the progress meter data */
struct UrlState state; /* struct for fields used for state info and
other dynamic purposes */
+#ifndef CURL_DISABLE_FTP
struct WildcardData wildcard; /* wildcard download state info */
+#endif
struct PureInfo info; /* stats, reports and info data */
struct curl_tlssessioninfo tsi; /* Information about the TLS session, only
valid after a client has asked for it */
diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c
index be6d6111e..6f452c169 100644
--- a/Utilities/cmcurl/lib/vauth/cleartext.c
+++ b/Utilities/cmcurl/lib/vauth/cleartext.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -25,6 +25,9 @@
#include "curl_setup.h"
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_POP3)
+
#include <curl/curl.h>
#include "urldata.h"
@@ -49,8 +52,9 @@
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The user name.
- * passwdp [in] - The user's password.
+ * authzid [in] - The authorization identity.
+ * authcid [in] - The authentication identity.
+ * passwd [in] - The password.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
* outlen [out] - The length of the output message.
@@ -58,36 +62,40 @@
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
- const char *userp,
- const char *passwdp,
+ const char *authzid,
+ const char *authcid,
+ const char *passwd,
char **outptr, size_t *outlen)
{
CURLcode result;
char *plainauth;
- size_t ulen;
+ size_t zlen;
+ size_t clen;
size_t plen;
size_t plainlen;
*outlen = 0;
*outptr = NULL;
- ulen = strlen(userp);
- plen = strlen(passwdp);
+ zlen = (authzid == NULL ? 0 : strlen(authzid));
+ clen = strlen(authcid);
+ plen = strlen(passwd);
/* Compute binary message length. Check for overflows. */
- if((ulen > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2)))
+ if(((zlen + clen) > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2)))
return CURLE_OUT_OF_MEMORY;
- plainlen = 2 * ulen + plen + 2;
+ plainlen = zlen + clen + plen + 2;
plainauth = malloc(plainlen);
if(!plainauth)
return CURLE_OUT_OF_MEMORY;
/* Calculate the reply */
- memcpy(plainauth, userp, ulen);
- plainauth[ulen] = '\0';
- memcpy(plainauth + ulen + 1, userp, ulen);
- plainauth[2 * ulen + 1] = '\0';
- memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
+ if(zlen != 0)
+ memcpy(plainauth, authzid, zlen);
+ plainauth[zlen] = '\0';
+ memcpy(plainauth + zlen + 1, authcid, clen);
+ plainauth[zlen + clen + 1] = '\0';
+ memcpy(plainauth + zlen + clen + 2, passwd, plen);
/* Base64 encode the reply */
result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen);
@@ -157,3 +165,5 @@ CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
/* This is the same formatting as the login message */
return Curl_auth_create_login_message(data, user, outptr, outlen);
}
+
+#endif /* if no users */
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index ab5156eb7..f9cdc9dd0 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -143,7 +143,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
{
int i;
for(i = 0; i < 16; i++)
- snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+ msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
/* Convert sha256 chunk to RFC7616 -suitable ascii string*/
@@ -152,7 +152,7 @@ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
{
int i;
for(i = 0; i < 32; i++)
- snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+ msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
/* Perform quoted-string escaping as described in RFC2616 and its errata */
@@ -432,7 +432,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/* Convert calculated 16 octet hex into 32 bytes string */
for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
+ msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
/* Generate our SPN */
spn = Curl_auth_build_spn(service, realm, NULL);
@@ -455,7 +455,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
Curl_MD5_final(ctxt, digest);
for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
+ msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
/* Now calculate the response hash */
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
@@ -485,7 +485,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
Curl_MD5_final(ctxt, digest);
for(i = 0; i < MD5_DIGEST_LEN; i++)
- snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
+ msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
/* Generate the response */
response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
@@ -785,8 +785,7 @@ static CURLcode _Curl_auth_create_digest_http_message(
return CURLE_OUT_OF_MEMORY;
if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
- /* We don't support auth-int for PUT or POST at the moment.
- TODO: replace hash of empty string with entity-body for PUT/POST */
+ /* We don't support auth-int for PUT or POST */
char hashed[65];
unsigned char *hashthis2;
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
index 928755735..fe8093e8b 100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2019, 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
@@ -146,7 +146,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
}
/* Generate our SPN */
- spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL);
+ spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
if(!spn) {
free(output_token);
free(input_token);
diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
index 55daec1ff..ea0a5f189 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
* Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
@@ -372,7 +372,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
}
/*
- * Curl_auth_gssapi_cleanup()
+ * Curl_auth_cleanup_gssapi()
*
* This is used to clean up the GSSAPI (Kerberos V5) specific data.
*
@@ -381,7 +381,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
* krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
*
*/
-void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
{
OM_uint32 minor_status;
diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
index cb11ed901..1f6e462bf 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2019, 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
@@ -474,7 +474,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
}
/*
- * Curl_auth_gssapi_cleanup()
+ * Curl_auth_cleanup_gssapi()
*
* This is used to clean up the GSSAPI (Kerberos V5) specific data.
*
@@ -483,7 +483,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
* krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
*
*/
-void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
{
/* Free our security context */
if(krb5->context) {
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index 11f42f504..047c2b5a3 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -182,10 +182,11 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
target_info_len = Curl_read16_le(&buffer[40]);
target_info_offset = Curl_read32_le(&buffer[44]);
if(target_info_len > 0) {
- if(((target_info_offset + target_info_len) > size) ||
+ if((target_info_offset >= size) ||
+ ((target_info_offset + target_info_len) > size) ||
(target_info_offset < 48)) {
infof(data, "NTLM handshake failure (bad type-2 message). "
- "Target Info Offset Len is set incorrect by the peer\n");
+ "Target Info Offset Len is set incorrect by the peer\n");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -402,45 +403,45 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
(void)hostname,
/* Clean up any former leftovers and initialise to defaults */
- Curl_auth_ntlm_cleanup(ntlm);
+ Curl_auth_cleanup_ntlm(ntlm);
#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
#else
#define NTLM2FLAG 0
#endif
- snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
- NTLMSSP_SIGNATURE "%c"
- "\x01%c%c%c" /* 32-bit type = 1 */
- "%c%c%c%c" /* 32-bit NTLM flag field */
- "%c%c" /* domain length */
- "%c%c" /* domain allocated space */
- "%c%c" /* domain name offset */
- "%c%c" /* 2 zeroes */
- "%c%c" /* host length */
- "%c%c" /* host allocated space */
- "%c%c" /* host name offset */
- "%c%c" /* 2 zeroes */
- "%s" /* host name */
- "%s", /* domain string */
- 0, /* trailing zero */
- 0, 0, 0, /* part of type-1 long */
-
- LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
- NTLMFLAG_REQUEST_TARGET |
- NTLMFLAG_NEGOTIATE_NTLM_KEY |
- NTLM2FLAG |
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
- SHORTPAIR(domlen),
- SHORTPAIR(domlen),
- SHORTPAIR(domoff),
- 0, 0,
- SHORTPAIR(hostlen),
- SHORTPAIR(hostlen),
- SHORTPAIR(hostoff),
- 0, 0,
- host, /* this is empty */
- domain /* this is empty */);
+ msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x01%c%c%c" /* 32-bit type = 1 */
+ "%c%c%c%c" /* 32-bit NTLM flag field */
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host name offset */
+ "%c%c" /* 2 zeroes */
+ "%s" /* host name */
+ "%s", /* domain string */
+ 0, /* trailing zero */
+ 0, 0, 0, /* part of type-1 long */
+
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0, 0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0, 0,
+ host, /* this is empty */
+ domain /* this is empty */);
/* Initial packet length */
size = 32 + hostlen + domlen;
@@ -562,7 +563,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
}
#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
- if(ntlm->target_info_len) {
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
unsigned char ntbuffer[0x18];
unsigned char entropy[8];
unsigned char ntlmv2hash[0x18];
@@ -599,7 +600,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
/* We don't support NTLM2 if we don't have USE_NTRESPONSES */
- if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
unsigned char ntbuffer[0x18];
unsigned char tmp[0x18];
unsigned char md5sum[MD5_DIGEST_LENGTH];
@@ -631,7 +632,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
/* End of NTLM2 Session code */
-
+ /* NTLM v2 session security is a misnomer because it is not NTLM v2.
+ It is NTLM v1 using the extended session security that is also
+ in NTLM v2 */
}
else
#endif
@@ -678,88 +681,88 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
hostoff = useroff + userlen;
/* Create the big type-3 message binary blob */
- size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
- NTLMSSP_SIGNATURE "%c"
- "\x03%c%c%c" /* 32-bit type = 3 */
-
- "%c%c" /* LanManager length */
- "%c%c" /* LanManager allocated space */
- "%c%c" /* LanManager offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* NT-response length */
- "%c%c" /* NT-response allocated space */
- "%c%c" /* NT-response offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* domain length */
- "%c%c" /* domain allocated space */
- "%c%c" /* domain name offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* user length */
- "%c%c" /* user allocated space */
- "%c%c" /* user offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* host length */
- "%c%c" /* host allocated space */
- "%c%c" /* host offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* session key length (unknown purpose) */
- "%c%c" /* session key allocated space (unknown purpose) */
- "%c%c" /* session key offset (unknown purpose) */
- "%c%c" /* 2 zeroes */
-
- "%c%c%c%c", /* flags */
-
- /* domain string */
- /* user string */
- /* host string */
- /* LanManager response */
- /* NT response */
-
- 0, /* zero termination */
- 0, 0, 0, /* type-3 long, the 24 upper bits */
-
- SHORTPAIR(0x18), /* LanManager response length, twice */
- SHORTPAIR(0x18),
- SHORTPAIR(lmrespoff),
- 0x0, 0x0,
+ size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x03%c%c%c" /* 32-bit type = 3 */
+
+ "%c%c" /* LanManager length */
+ "%c%c" /* LanManager allocated space */
+ "%c%c" /* LanManager offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* NT-response length */
+ "%c%c" /* NT-response allocated space */
+ "%c%c" /* NT-response offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* user length */
+ "%c%c" /* user allocated space */
+ "%c%c" /* user offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* session key length (unknown purpose) */
+ "%c%c" /* session key allocated space (unknown purpose) */
+ "%c%c" /* session key offset (unknown purpose) */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c%c%c", /* flags */
+
+ /* domain string */
+ /* user string */
+ /* host string */
+ /* LanManager response */
+ /* NT response */
+
+ 0, /* zero termination */
+ 0, 0, 0, /* type-3 long, the 24 upper bits */
+
+ SHORTPAIR(0x18), /* LanManager response length, twice */
+ SHORTPAIR(0x18),
+ SHORTPAIR(lmrespoff),
+ 0x0, 0x0,
#ifdef USE_NTRESPONSES
- SHORTPAIR(ntresplen), /* NT-response length, twice */
- SHORTPAIR(ntresplen),
- SHORTPAIR(ntrespoff),
- 0x0, 0x0,
+ SHORTPAIR(ntresplen), /* NT-response length, twice */
+ SHORTPAIR(ntresplen),
+ SHORTPAIR(ntrespoff),
+ 0x0, 0x0,
#else
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
#endif
- SHORTPAIR(domlen),
- SHORTPAIR(domlen),
- SHORTPAIR(domoff),
- 0x0, 0x0,
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0x0, 0x0,
- SHORTPAIR(userlen),
- SHORTPAIR(userlen),
- SHORTPAIR(useroff),
- 0x0, 0x0,
+ SHORTPAIR(userlen),
+ SHORTPAIR(userlen),
+ SHORTPAIR(useroff),
+ 0x0, 0x0,
- SHORTPAIR(hostlen),
- SHORTPAIR(hostlen),
- SHORTPAIR(hostoff),
- 0x0, 0x0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
- LONGQUARTET(ntlm->flags));
+ LONGQUARTET(ntlm->flags));
DEBUGASSERT(size == 64);
DEBUGASSERT(size == (size_t)lmrespoff);
@@ -776,11 +779,14 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
});
#ifdef USE_NTRESPONSES
- if(size < (NTLM_BUFSIZE - ntresplen)) {
- DEBUGASSERT(size == (size_t)ntrespoff);
- memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
- size += ntresplen;
+ /* ntresplen + size should not be risking an integer overflow here */
+ if(ntresplen + size > sizeof(ntlmbuf)) {
+ failf(data, "incoming NTLM message too big");
+ return CURLE_OUT_OF_MEMORY;
}
+ DEBUGASSERT(size == (size_t)ntrespoff);
+ memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
+ size += ntresplen;
DEBUG_OUT({
fprintf(stderr, "\n ntresp=");
@@ -838,22 +844,22 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
/* Return with binary blob encoded into base64 */
result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
- Curl_auth_ntlm_cleanup(ntlm);
+ Curl_auth_cleanup_ntlm(ntlm);
return result;
}
/*
-* Curl_auth_ntlm_cleanup()
-*
-* This is used to clean up the NTLM specific data.
-*
-* Parameters:
-*
-* ntlm [in/out] - The NTLM data struct being cleaned up.
-*
-*/
-void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+ * Curl_auth_cleanup_ntlm()
+ *
+ * This is used to clean up the NTLM specific data.
+ *
+ * Parameters:
+ *
+ * ntlm [in/out] - The NTLM data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
{
/* Free the target info */
Curl_safefree(ntlm->target_info);
diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
index b66cfe737..589cca16c 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -95,7 +95,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
/* Clean up any former leftovers and initialise to defaults */
- Curl_auth_ntlm_cleanup(ntlm);
+ Curl_auth_cleanup_ntlm(ntlm);
/* Query the security package for NTLM */
status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
@@ -249,7 +249,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
char **outptr, size_t *outlen)
{
CURLcode result = CURLE_OK;
- SecBuffer type_2_buf;
+ SecBuffer type_2_bufs[2];
SecBuffer type_3_buf;
SecBufferDesc type_2_desc;
SecBufferDesc type_3_desc;
@@ -261,12 +261,39 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
(void) userp;
/* Setup the type-2 "input" security buffer */
- type_2_desc.ulVersion = SECBUFFER_VERSION;
- type_2_desc.cBuffers = 1;
- type_2_desc.pBuffers = &type_2_buf;
- type_2_buf.BufferType = SECBUFFER_TOKEN;
- type_2_buf.pvBuffer = ntlm->input_token;
- type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len);
+ type_2_desc.ulVersion = SECBUFFER_VERSION;
+ type_2_desc.cBuffers = 1;
+ type_2_desc.pBuffers = &type_2_bufs[0];
+ type_2_bufs[0].BufferType = SECBUFFER_TOKEN;
+ type_2_bufs[0].pvBuffer = ntlm->input_token;
+ type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* ssl context comes from schannel.
+ * When extended protection is used in IIS server,
+ * we have to pass a second SecBuffer to the SecBufferDesc
+ * otherwise IIS will not pass the authentication (401 response).
+ * Minimum supported version is Windows 7.
+ * https://docs.microsoft.com/en-us/security-updates
+ * /SecurityAdvisories/2009/973811
+ */
+ if(ntlm->sslContext) {
+ SEC_CHANNEL_BINDINGS channelBindings;
+ SecPkgContext_Bindings pkgBindings;
+ pkgBindings.Bindings = &channelBindings;
+ status = s_pSecFn->QueryContextAttributes(
+ ntlm->sslContext,
+ SECPKG_ATTR_ENDPOINT_BINDINGS,
+ &pkgBindings
+ );
+ if(status == SEC_E_OK) {
+ type_2_desc.cBuffers++;
+ type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+ type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength;
+ type_2_bufs[1].pvBuffer = pkgBindings.Bindings;
+ }
+ }
+#endif
/* Setup the type-3 "output" security buffer */
type_3_desc.ulVersion = SECBUFFER_VERSION;
@@ -296,13 +323,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
result = Curl_base64_encode(data, (char *) ntlm->output_token,
type_3_buf.cbBuffer, outptr, outlen);
- Curl_auth_ntlm_cleanup(ntlm);
+ Curl_auth_cleanup_ntlm(ntlm);
return result;
}
/*
- * Curl_auth_ntlm_cleanup()
+ * Curl_auth_cleanup_ntlm()
*
* This is used to clean up the NTLM specific data.
*
@@ -311,7 +338,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
* ntlm [in/out] - The NTLM data struct being cleaned up.
*
*/
-void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
{
/* Free our security context */
if(ntlm->context) {
diff --git a/Utilities/cmcurl/lib/vauth/oauth2.c b/Utilities/cmcurl/lib/vauth/oauth2.c
index 6288f89a3..b4e9f8e70 100644
--- a/Utilities/cmcurl/lib/vauth/oauth2.c
+++ b/Utilities/cmcurl/lib/vauth/oauth2.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -24,6 +24,9 @@
#include "curl_setup.h"
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_POP3)
+
#include <curl/curl.h>
#include "urldata.h"
@@ -46,8 +49,8 @@
*
* data[in] - The session handle.
* user[in] - The user name.
- * host[in] - The host name(for OAUTHBEARER).
- * port[in] - The port(for OAUTHBEARER when not Port 80).
+ * host[in] - The host name.
+ * port[in] - The port(when not Port 80).
* bearer[in] - The bearer token.
* outptr[in / out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
@@ -66,13 +69,11 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
char *oauth = NULL;
/* Generate the message */
- if(host == NULL && (port == 0 || port == 80))
- oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
- else if(port == 0 || port == 80)
- oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host,
+ if(port == 0 || port == 80)
+ oauth = aprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host,
bearer);
else
- oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user,
+ oauth = aprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user,
host, port, bearer);
if(!oauth)
return CURLE_OUT_OF_MEMORY;
@@ -84,3 +85,42 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
return result;
}
+
+/*
+ * Curl_auth_create_xoauth_bearer_message()
+ *
+ * This is used to generate an already encoded XOAuth 2.0 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data[in] - The session handle.
+ * user[in] - The user name.
+ * bearer[in] - The bearer token.
+ * outptr[in / out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen[out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data,
+ const char *user,
+ const char *bearer,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Generate the message */
+ char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
+ if(!xoauth)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Base64 encode the reply */
+ result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen);
+
+ free(xoauth);
+
+ return result;
+}
+#endif /* disabled, no users */
+
diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
index 4a48bdd20..5d43e1100 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -97,7 +97,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* We finished successfully our part of authentication, but server
* rejected it (since we're again here). Exit with an error since we
* can't invent anything better */
- Curl_auth_spnego_cleanup(nego);
+ Curl_auth_cleanup_spnego(nego);
return CURLE_LOGIN_DENIED;
}
@@ -170,7 +170,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
major_status, minor_status);
- return CURLE_OUT_OF_MEMORY;
+ return CURLE_LOGIN_DENIED;
}
if(!output_token.value || !output_token.length) {
@@ -238,7 +238,7 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
}
/*
- * Curl_auth_spnego_cleanup()
+ * Curl_auth_cleanup_spnego()
*
* This is used to clean up the SPNEGO (Negotiate) specific data.
*
@@ -247,7 +247,7 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
* nego [in/out] - The Negotiate data struct being cleaned up.
*
*/
-void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
{
OM_uint32 minor_status;
@@ -273,6 +273,10 @@ void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
/* Reset any variables */
nego->status = 0;
+ nego->noauthpersist = FALSE;
+ nego->havenoauthpersist = FALSE;
+ nego->havenegdata = FALSE;
+ nego->havemultiplerequests = FALSE;
}
#endif /* HAVE_GSSAPI && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
index 77d1895a5..4b21cc769 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -92,7 +92,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
size_t chlglen = 0;
unsigned char *chlg = NULL;
PSecPkgInfo SecurityPackage;
- SecBuffer chlg_buf;
+ SecBuffer chlg_buf[2];
SecBuffer resp_buf;
SecBufferDesc chlg_desc;
SecBufferDesc resp_desc;
@@ -107,7 +107,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* We finished successfully our part of authentication, but server
* rejected it (since we're again here). Exit with an error since we
* can't invent anything better */
- Curl_auth_spnego_cleanup(nego);
+ Curl_auth_cleanup_spnego(nego);
return CURLE_LOGIN_DENIED;
}
@@ -189,12 +189,39 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
}
/* Setup the challenge "input" security buffer */
- chlg_desc.ulVersion = SECBUFFER_VERSION;
- chlg_desc.cBuffers = 1;
- chlg_desc.pBuffers = &chlg_buf;
- chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = chlg;
- chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 1;
+ chlg_desc.pBuffers = &chlg_buf[0];
+ chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+ chlg_buf[0].pvBuffer = chlg;
+ chlg_buf[0].cbBuffer = curlx_uztoul(chlglen);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* ssl context comes from Schannel.
+ * When extended protection is used in IIS server,
+ * we have to pass a second SecBuffer to the SecBufferDesc
+ * otherwise IIS will not pass the authentication (401 response).
+ * Minimum supported version is Windows 7.
+ * https://docs.microsoft.com/en-us/security-updates
+ * /SecurityAdvisories/2009/973811
+ */
+ if(nego->sslContext) {
+ SEC_CHANNEL_BINDINGS channelBindings;
+ SecPkgContext_Bindings pkgBindings;
+ pkgBindings.Bindings = &channelBindings;
+ nego->status = s_pSecFn->QueryContextAttributes(
+ nego->sslContext,
+ SECPKG_ATTR_ENDPOINT_BINDINGS,
+ &pkgBindings
+ );
+ if(nego->status == SEC_E_OK) {
+ chlg_desc.cBuffers++;
+ chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+ chlg_buf[1].cbBuffer = pkgBindings.BindingsLength;
+ chlg_buf[1].pvBuffer = pkgBindings.Bindings;
+ }
+ }
+#endif
}
/* Setup the response "output" security buffer */
@@ -221,8 +248,9 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
free(chlg);
if(GSS_ERROR(nego->status)) {
+ char buffer[STRERROR_LEN];
failf(data, "InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(data->easy_conn, nego->status));
+ Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));
return CURLE_OUT_OF_MEMORY;
}
@@ -279,7 +307,7 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
}
/*
- * Curl_auth_spnego_cleanup()
+ * Curl_auth_cleanup_spnego()
*
* This is used to clean up the SPNEGO (Negotiate) specific data.
*
@@ -288,7 +316,7 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
* nego [in/out] - The Negotiate data struct being cleaned up.
*
*/
-void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
{
/* Free our security context */
if(nego->context) {
@@ -315,6 +343,10 @@ void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
/* Reset any variables */
nego->status = 0;
nego->token_max = 0;
+ nego->noauthpersist = FALSE;
+ nego->havenoauthpersist = FALSE;
+ nego->havenegdata = FALSE;
+ nego->havemultiplerequests = FALSE;
}
#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c
index 502d443ab..a9c5c9c4f 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.c
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2019, 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
@@ -105,26 +105,26 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
#endif /* USE_WINDOWS_SSPI */
/*
-* Curl_auth_user_contains_domain()
-*
-* This is used to test if the specified user contains a Windows domain name as
-* follows:
-*
-* User\Domain (Down-level Logon Name)
-* User/Domain (curl Down-level format - for compatibility with existing code)
-* User@Domain (User Principal Name)
-*
-* Note: The user name may be empty when using a GSS-API library or Windows SSPI
-* as the user and domain are either obtained from the credentials cache when
-* using GSS-API or via the currently logged in user's credentials when using
-* Windows SSPI.
-*
-* Parameters:
-*
-* user [in] - The user name.
-*
-* Returns TRUE on success; otherwise FALSE.
-*/
+ * Curl_auth_user_contains_domain()
+ *
+ * This is used to test if the specified user contains a Windows domain name as
+ * follows:
+ *
+ * Domain\User (Down-level Logon Name)
+ * Domain/User (curl Down-level format - for compatibility with existing code)
+ * User@Domain (User Principal Name)
+ *
+ * Note: The user name may be empty when using a GSS-API library or Windows
+ * SSPI as the user and domain are either obtained from the credentials cache
+ * when using GSS-API or via the currently logged in user's credentials when
+ * using Windows SSPI.
+ *
+ * Parameters:
+ *
+ * user [in] - The user name.
+ *
+ * Returns TRUE on success; otherwise FALSE.
+ */
bool Curl_auth_user_contains_domain(const char *user)
{
bool valid = FALSE;
diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h
index f43064211..73bd25ed5 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.h
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2019, 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
@@ -60,8 +60,9 @@ bool Curl_auth_user_contains_domain(const char *user);
/* This is used to generate a base64 encoded PLAIN cleartext message */
CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
- const char *userp,
- const char *passwdp,
+ const char *authzid,
+ const char *authcid,
+ const char *passwd,
char **outptr, size_t *outlen);
/* This is used to generate a base64 encoded LOGIN cleartext message */
@@ -141,7 +142,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
char **outptr, size_t *outlen);
/* This is used to clean up the NTLM specific data */
-void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm);
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
#endif /* USE_NTLM */
/* This is used to generate a base64 encoded OAuth 2.0 message */
@@ -151,6 +152,13 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
const long port,
const char *bearer,
char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded XOAuth 2.0 message */
+CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data,
+ const char *user,
+ const char *bearer,
+ char **outptr, size_t *outlen);
+
#if defined(USE_KERBEROS5)
/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
bool Curl_auth_is_gssapi_supported(void);
@@ -176,7 +184,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
size_t *outlen);
/* This is used to clean up the GSSAPI specific data */
-void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5);
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5);
#endif /* USE_KERBEROS5 */
#if defined(USE_SPNEGO)
@@ -200,7 +208,7 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
char **outptr, size_t *outlen);
/* This is used to clean up the SPNEGO specifiec data */
-void Curl_auth_spnego_cleanup(struct negotiatedata *nego);
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego);
#endif /* USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index 05c2cd8b0..14b0531d3 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -31,7 +31,7 @@
#ifdef USE_ARES
# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+ (defined(WIN32) || defined(__SYMBIAN32__))
# define CARES_STATICLIB
# endif
# include <ares.h>
@@ -95,7 +95,7 @@ static size_t brotli_version(char *buf, size_t bufsz)
unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
unsigned int patch = brotli_version & 0x00000FFF;
- return snprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+ return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
}
#endif
@@ -126,12 +126,12 @@ char *curl_version(void)
}
#ifdef HAVE_LIBZ
- len = snprintf(ptr, left, " zlib/%s", zlibVersion());
+ len = msnprintf(ptr, left, " zlib/%s", zlibVersion());
left -= len;
ptr += len;
#endif
#ifdef HAVE_BROTLI
- len = snprintf(ptr, left, "%s", " brotli/");
+ len = msnprintf(ptr, left, "%s", " brotli/");
left -= len;
ptr += len;
len = brotli_version(ptr, left);
@@ -140,45 +140,45 @@ char *curl_version(void)
#endif
#ifdef USE_ARES
/* this function is only present in c-ares, not in the original ares */
- len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
+ len = msnprintf(ptr, left, " c-ares/%s", ares_version(NULL));
left -= len;
ptr += len;
#endif
#ifdef USE_LIBIDN2
if(idn2_check_version(IDN2_VERSION)) {
- len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL));
+ len = msnprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL));
left -= len;
ptr += len;
}
#endif
#ifdef USE_LIBPSL
- len = snprintf(ptr, left, " libpsl/%s", psl_get_version());
+ len = msnprintf(ptr, left, " libpsl/%s", psl_get_version());
left -= len;
ptr += len;
#endif
#ifdef USE_WIN32_IDN
- len = snprintf(ptr, left, " WinIDN");
+ len = msnprintf(ptr, left, " WinIDN");
left -= len;
ptr += len;
#endif
#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
#ifdef _LIBICONV_VERSION
- len = snprintf(ptr, left, " iconv/%d.%d",
- _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
+ len = msnprintf(ptr, left, " iconv/%d.%d",
+ _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
#else
/* version unknown */
- len = snprintf(ptr, left, " iconv");
+ len = msnprintf(ptr, left, " iconv");
#endif /* _LIBICONV_VERSION */
left -= len;
ptr += len;
#endif
#ifdef USE_LIBSSH2
- len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION);
+ len = msnprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION);
left -= len;
ptr += len;
#endif
#ifdef USE_LIBSSH
- len = snprintf(ptr, left, " libssh/%s", CURL_LIBSSH_VERSION);
+ len = msnprintf(ptr, left, " libssh/%s", CURL_LIBSSH_VERSION);
left -= len;
ptr += len;
#endif
@@ -197,14 +197,14 @@ char *curl_version(void)
else
suff[0] = '\0';
- snprintf(ptr, left, " librtmp/%d.%d%s",
- RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
- suff);
+ msnprintf(ptr, left, " librtmp/%d.%d%s",
+ RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+ suff);
/*
If another lib version is added below this one, this code would
also have to do:
- len = what snprintf() returned
+ len = what msnprintf() returned
left -= len;
ptr += len;
@@ -212,6 +212,10 @@ char *curl_version(void)
}
#endif
+ /* Silent scan-build even if librtmp is not enabled. */
+ (void) left;
+ (void) ptr;
+
initialized = true;
return version;
}
@@ -270,7 +274,7 @@ static const char * const protocols[] = {
#ifndef CURL_DISABLE_RTSP
"rtsp",
#endif
-#if defined(USE_LIBSSH) || defined(USE_LIBSSH2)
+#if defined(USE_SSH)
"scp",
"sftp",
#endif
@@ -366,6 +370,9 @@ static curl_version_info_data version_info = {
#if defined(HAVE_BROTLI)
| CURL_VERSION_BROTLI
#endif
+#if defined(USE_ALTSVC)
+ | CURL_VERSION_ALTSVC
+#endif
,
NULL, /* ssl_version */
0, /* ssl_version_num, this is kept at zero */
@@ -383,12 +390,16 @@ static curl_version_info_data version_info = {
curl_version_info_data *curl_version_info(CURLversion stamp)
{
static bool initialized;
-#if defined(USE_LIBSSH) || defined(USE_LIBSSH2)
+#if defined(USE_SSH)
static char ssh_buffer[80];
#endif
#ifdef USE_SSL
+#ifdef CURL_WITH_MULTI_SSL
+ static char ssl_buffer[200];
+#else
static char ssl_buffer[80];
#endif
+#endif
#ifdef HAVE_BROTLI
static char brotli_buffer[80];
#endif
@@ -436,10 +447,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#endif
#if defined(USE_LIBSSH2)
- snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
+ msnprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
version_info.libssh_version = ssh_buffer;
#elif defined(USE_LIBSSH)
- snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh/%s", CURL_LIBSSH_VERSION);
+ msnprintf(ssh_buffer, sizeof(ssh_buffer), "libssh/%s", CURL_LIBSSH_VERSION);
version_info.libssh_version = ssh_buffer;
#endif
diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c
deleted file mode 100644
index b262392a0..000000000
--- a/Utilities/cmcurl/lib/vtls/axtls.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
- * Copyright (C) 2010 - 2018, 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.
- *
- ***************************************************************************/
-
-/*
- * Source file for all axTLS-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- */
-
-#include "curl_setup.h"
-
-#ifdef USE_AXTLS
-
-#error axTLS support has been disabled in curl due to doubts about quality,
-#error user dedication and a lack of use/testing. We urge users to consider
-#error using a more established TLS backend instead.
-
-#include <axTLS/config.h>
-#include <axTLS/ssl.h>
-#include "axtls.h"
-
-#include "sendf.h"
-#include "inet_pton.h"
-#include "vtls.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "curl_printf.h"
-#include "hostcheck.h"
-#include <unistd.h>
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-struct ssl_backend_data {
- SSL_CTX* ssl_ctx;
- SSL* ssl;
-};
-
-#define BACKEND connssl->backend
-
-static CURLcode map_error_to_curl(int axtls_err)
-{
- switch(axtls_err) {
- case SSL_ERROR_NOT_SUPPORTED:
- case SSL_ERROR_INVALID_VERSION:
- case -70: /* protocol version alert from server */
- return CURLE_UNSUPPORTED_PROTOCOL;
- break;
- case SSL_ERROR_NO_CIPHER:
- return CURLE_SSL_CIPHER;
- break;
- case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
- case SSL_ERROR_NO_CERT_DEFINED:
- case -42: /* bad certificate alert from server */
- case -43: /* unsupported cert alert from server */
- case -44: /* cert revoked alert from server */
- case -45: /* cert expired alert from server */
- case -46: /* cert unknown alert from server */
- return CURLE_SSL_CERTPROBLEM;
- break;
- case SSL_X509_ERROR(X509_NOT_OK):
- case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
- case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
- case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
- case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
- case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
- case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
- case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
- case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
- return CURLE_PEER_FAILED_VERIFICATION;
- break;
- case -48: /* unknown ca alert from server */
- return CURLE_SSL_CACERT;
- break;
- case -49: /* access denied alert from server */
- return CURLE_REMOTE_ACCESS_DENIED;
- break;
- case SSL_ERROR_CONN_LOST:
- case SSL_ERROR_SOCK_SETUP_FAILURE:
- case SSL_ERROR_INVALID_HANDSHAKE:
- case SSL_ERROR_INVALID_PROT_MSG:
- case SSL_ERROR_INVALID_HMAC:
- case SSL_ERROR_INVALID_SESSION:
- case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */
- case SSL_ERROR_FINISHED_INVALID:
- case SSL_ERROR_NO_CLIENT_RENOG:
- default:
- return CURLE_SSL_CONNECT_ERROR;
- break;
- }
-}
-
-static Curl_recv axtls_recv;
-static Curl_send axtls_send;
-
-static void free_ssl_structs(struct ssl_connect_data *connssl)
-{
- if(BACKEND->ssl) {
- ssl_free(BACKEND->ssl);
- BACKEND->ssl = NULL;
- }
- if(BACKEND->ssl_ctx) {
- ssl_ctx_free(BACKEND->ssl_ctx);
- BACKEND->ssl_ctx = NULL;
- }
-}
-
-/*
- * For both blocking and non-blocking connects, this function sets up the
- * ssl context and state. This function is called after the TCP connect
- * has completed.
- */
-static CURLcode connect_prep(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct Curl_easy *data = conn->data;
- SSL_CTX *ssl_ctx;
- SSL *ssl = NULL;
- int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
- int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
- int i, ssl_fcn_return;
-
- /* Assuming users will not compile in custom key/cert to axTLS.
- * Also, even for blocking connects, use axTLS non-blocking feature.
- */
- uint32_t client_option = SSL_NO_DEFAULT_KEY |
- SSL_SERVER_VERIFY_LATER |
- SSL_CONNECT_IN_PARTS;
-
- if(connssl->state == ssl_connection_complete)
- /* to make us tolerant against being called more than once for the
- same connection */
- return CURLE_OK;
-
- if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
- failf(data, "axtls does not support CURL_SSLVERSION_MAX");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-
- /* axTLS only supports TLSv1 */
- /* check to see if we've been told to use an explicit SSL/TLS version */
- switch(SSL_CONN_CONFIG(version)) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- break;
- default:
- failf(data, "axTLS only supports TLS 1.0 and 1.1, "
- "and it cannot be specified which one to use");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-#ifdef AXTLSDEBUG
- client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
-#endif /* AXTLSDEBUG */
-
- /* Allocate an SSL_CTX struct */
- ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
- if(ssl_ctx == NULL) {
- failf(data, "unable to create client SSL context");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- BACKEND->ssl_ctx = ssl_ctx;
- BACKEND->ssl = NULL;
-
- /* Load the trusted CA cert bundle file */
- if(SSL_CONN_CONFIG(CAfile)) {
- if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT,
- SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) {
- infof(data, "error reading ca cert file %s \n",
- SSL_CONN_CONFIG(CAfile));
- if(SSL_CONN_CONFIG(verifypeer)) {
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else
- infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile));
- }
-
- /* gtls.c tasks we're skipping for now:
- * 1) certificate revocation list checking
- * 2) dns name assignment to host
- * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore
- * 4) set certificate priority. axTLS ignores type and sends certs in
- * order added. can probably ignore this.
- */
-
- /* Load client certificate */
- if(SSL_SET_OPTION(cert)) {
- i = 0;
- /* Instead of trying to analyze cert type here, let axTLS try them all. */
- while(cert_types[i] != 0) {
- ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
- SSL_SET_OPTION(cert), NULL);
- if(ssl_fcn_return == SSL_OK) {
- infof(data, "successfully read cert file %s \n",
- SSL_SET_OPTION(cert));
- break;
- }
- i++;
- }
- /* Tried all cert types, none worked. */
- if(cert_types[i] == 0) {
- failf(data, "%s is not x509 or pkcs12 format",
- SSL_SET_OPTION(cert));
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* Load client key.
- If a pkcs12 file successfully loaded a cert, then there's nothing to do
- because the key has already been loaded. */
- if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) {
- i = 0;
- /* Instead of trying to analyze key type here, let axTLS try them all. */
- while(key_types[i] != 0) {
- ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
- SSL_SET_OPTION(key), NULL);
- if(ssl_fcn_return == SSL_OK) {
- infof(data, "successfully read key file %s \n",
- SSL_SET_OPTION(key));
- break;
- }
- i++;
- }
- /* Tried all key types, none worked. */
- if(key_types[i] == 0) {
- failf(data, "Failure: %s is not a supported key file",
- SSL_SET_OPTION(key));
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* gtls.c does more here that is being left out for now
- * 1) set session credentials. can probably ignore since axtls puts this
- * info in the ssl_ctx struct
- * 2) setting up callbacks. these seem gnutls specific
- */
-
- if(SSL_SET_OPTION(primary.sessionid)) {
- const uint8_t *ssl_sessionid;
- size_t ssl_idsize;
-
- /* In axTLS, handshaking happens inside ssl_client_new. */
- Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize,
- sockindex)) {
- /* we got a session id, use it! */
- infof(data, "SSL re-using session ID\n");
- ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
- ssl_sessionid, (uint8_t)ssl_idsize, NULL);
- }
- Curl_ssl_sessionid_unlock(conn);
- }
-
- if(!ssl)
- ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL);
-
- BACKEND->ssl = ssl;
- return CURLE_OK;
-}
-
-static void Curl_axtls_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- infof(conn->data, " Curl_axtls_close\n");
-
- /* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl);
- axTLS compat layer does nothing for SSL_shutdown */
-
- /* The following line is from openssl.c. There seems to be no axTLS
- equivalent. ssl_free and ssl_ctx_free close things.
- SSL_set_connect_state(connssl->handle); */
-
- free_ssl_structs(connssl);
-}
-
-/*
- * For both blocking and non-blocking connects, this function finalizes the
- * SSL connection.
- */
-static CURLcode connect_finish(struct connectdata *conn, int sockindex)
-{
- struct Curl_easy *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SSL *ssl = BACKEND->ssl;
- const char *peer_CN;
- uint32_t dns_altname_index;
- const char *dns_altname;
- int8_t found_subject_alt_names = 0;
- int8_t found_subject_alt_name_matching_conn = 0;
- 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;
-
- /* Here, gtls.c gets the peer certificates and fails out depending on
- * settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
- */
-
- /* Verify server's certificate */
- if(SSL_CONN_CONFIG(verifypeer)) {
- if(ssl_verify_cert(ssl) != SSL_OK) {
- Curl_axtls_close(conn, sockindex);
- failf(data, "server cert verify failed");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- }
- else
- infof(data, "\t server certificate verification SKIPPED\n");
-
- /* Here, gtls.c does issuer verification. axTLS has no straightforward
- * equivalent, so omitting for now.*/
-
- /* Here, gtls.c does the following
- * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but
- * it seems useful. This is now implemented, by Oscar Koeroo
- * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert
- * 3) displays a bunch of cert information. axTLS doesn't support most of
- * this, but a couple fields are available.
- */
-
- /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
- risk of an inifite loop */
- for(dns_altname_index = 0; ; dns_altname_index++) {
- dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
- if(dns_altname == NULL) {
- break;
- }
- found_subject_alt_names = 1;
-
- infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
- dns_altname, hostname);
- if(Curl_cert_hostcheck(dns_altname, hostname)) {
- found_subject_alt_name_matching_conn = 1;
- break;
- }
- }
-
- /* RFC2818 checks */
- if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
- if(SSL_CONN_CONFIG(verifyhost)) {
- /* Break connection ! */
- Curl_axtls_close(conn, sockindex);
- failf(data, "\tsubjectAltName(s) do not match %s\n", dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\tsubjectAltName(s) do not match %s\n", dispname);
- }
- else if(found_subject_alt_names == 0) {
- /* Per RFC2818, when no Subject Alt Names were available, examine the peer
- CN as a legacy fallback */
- peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
- if(peer_CN == NULL) {
- if(SSL_CONN_CONFIG(verifyhost)) {
- Curl_axtls_close(conn, sockindex);
- failf(data, "unable to obtain common name from peer certificate");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "unable to obtain common name from peer certificate");
- }
- else {
- if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
- if(SSL_CONN_CONFIG(verifyhost)) {
- /* Break connection ! */
- Curl_axtls_close(conn, sockindex);
- failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, dispname);
- }
- }
- }
-
- /* General housekeeping */
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = axtls_recv;
- conn->send[sockindex] = axtls_send;
-
- /* Put our freshly minted SSL session in cache */
- if(SSL_SET_OPTION(primary.sessionid)) {
- const uint8_t *ssl_sessionid = ssl_get_session_id(ssl);
- size_t ssl_idsize = ssl_get_session_id_size(ssl);
- Curl_ssl_sessionid_lock(conn);
- if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize,
- sockindex) != CURLE_OK)
- infof(data, "failed to add session to cache\n");
- Curl_ssl_sessionid_unlock(conn);
- }
-
- return CURLE_OK;
-}
-
-/*
- * Use axTLS's non-blocking connection feature to open an SSL connection.
- * This is called after a TCP connection is already established.
- */
-static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CURLcode conn_step;
- int ssl_fcn_return;
- int i;
-
- *done = FALSE;
- /* connectdata is calloc'd and connecting_state is only changed in this
- function, so this is safe, as the state is effectively initialized. */
- if(connssl->connecting_state == ssl_connect_1) {
- conn_step = connect_prep(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
- connssl->connecting_state = ssl_connect_2;
- }
-
- if(connssl->connecting_state == ssl_connect_2) {
- /* Check to make sure handshake was ok. */
- if(ssl_handshake_status(BACKEND->ssl) != SSL_OK) {
- /* Loop to perform more work in between sleeps. This is work around the
- fact that axtls does not expose any knowledge about when work needs
- to be performed. This can save ~25% of time on SSL handshakes. */
- for(i = 0; i<5; i++) {
- ssl_fcn_return = ssl_read(BACKEND->ssl, NULL);
- if(ssl_fcn_return < 0) {
- Curl_axtls_close(conn, sockindex);
- ssl_display_error(ssl_fcn_return); /* goes to stdout. */
- return map_error_to_curl(ssl_fcn_return);
- }
- return CURLE_OK;
- }
- }
- infof(conn->data, "handshake completed successfully\n");
- connssl->connecting_state = ssl_connect_3;
- }
-
- if(connssl->connecting_state == ssl_connect_3) {
- conn_step = connect_finish(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- /* Reset connect state */
- connssl->connecting_state = ssl_connect_1;
-
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* Unrecognized state. Things are very bad. */
- connssl->state = ssl_connection_none;
- connssl->connecting_state = ssl_connect_1;
- /* Return value perhaps not strictly correct, but distinguishes the issue.*/
- return CURLE_BAD_FUNCTION_ARGUMENT;
-}
-
-
-/*
- * This function is called after the TCP connect has completed. Setup the TLS
- * layer and do all necessary magic for a blocking connect.
- */
-static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex)
-{
- struct Curl_easy *data = conn->data;
- CURLcode conn_step = connect_prep(conn, sockindex);
- int ssl_fcn_return;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SSL *ssl = BACKEND->ssl;
- long timeout_ms;
-
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- /* Check to make sure handshake was ok. */
- while(ssl_handshake_status(ssl) != SSL_OK) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- ssl_fcn_return = ssl_read(ssl, NULL);
- if(ssl_fcn_return < 0) {
- Curl_axtls_close(conn, sockindex);
- ssl_display_error(ssl_fcn_return); /* goes to stdout. */
- return map_error_to_curl(ssl_fcn_return);
- }
- /* TODO: avoid polling */
- Curl_wait_ms(10);
- }
- infof(conn->data, "handshake completed successfully\n");
-
- conn_step = connect_finish(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- return CURLE_OK;
-}
-
-/* return number of sent (non-SSL) bytes */
-static ssize_t axtls_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *err)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
- int rc = ssl_write(BACKEND->ssl, mem, (int)len);
-
- infof(conn->data, " axtls_send\n");
-
- if(rc < 0) {
- *err = map_error_to_curl(rc);
- rc = -1; /* generic error code for send failure */
- }
-
- *err = CURLE_OK;
- return rc;
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
-{
- /* Outline taken from openssl.c since functions are in axTLS compat layer.
- axTLS's error set is much smaller, so a lot of error-handling was removed.
- */
- int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct Curl_easy *data = conn->data;
- uint8_t *buf;
- ssize_t nread;
-
- infof(conn->data, " Curl_axtls_shutdown\n");
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(BACKEND->ssl);
- */
-
- if(BACKEND->ssl) {
- int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. buf is managed internally by
- axTLS and will be released upon calling ssl_free via
- free_ssl_structs. */
- nread = (ssize_t)ssl_read(BACKEND->ssl, &buf);
-
- if(nread < SSL_OK) {
- failf(data, "close notify alert not received during shutdown");
- retval = -1;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- }
-
- free_ssl_structs(connssl);
- }
- return retval;
-}
-
-static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *err)
-{
- struct ssl_connect_data *connssl = &conn->ssl[num];
- ssize_t ret = 0;
- uint8_t *read_buf;
-
- infof(conn->data, " axtls_recv\n");
-
- *err = CURLE_OK;
- if(connssl) {
- ret = ssl_read(BACKEND->ssl, &read_buf);
- if(ret > SSL_OK) {
- /* ssl_read returns SSL_OK if there is more data to read, so if it is
- larger, then all data has been read already. */
- memcpy(buf, read_buf,
- (size_t)ret > buffersize ? buffersize : (size_t)ret);
- }
- else if(ret == SSL_OK) {
- /* more data to be read, signal caller to call again */
- *err = CURLE_AGAIN;
- ret = -1;
- }
- else if(ret == -3) {
- /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
- team approves proposed fix. */
- Curl_axtls_close(conn, num);
- }
- else {
- failf(conn->data, "axTLS recv error (%d)", ret);
- *err = map_error_to_curl((int) ret);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-/*
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-static int Curl_axtls_check_cxn(struct connectdata *conn)
-{
- /* openssl.c line:
- rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1);
- axTLS compat layer always returns the last argument, so connection is
- always alive? */
-
- infof(conn->data, " Curl_axtls_check_cxn\n");
- return 1; /* connection still in place */
-}
-
-static void Curl_axtls_session_free(void *ptr)
-{
- (void)ptr;
- /* free the ID */
- /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL
- compatibility layer does nothing, so we do nothing too. */
-}
-
-static size_t Curl_axtls_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, "axTLS/%s", ssl_version());
-}
-
-static CURLcode Curl_axtls_random(struct Curl_easy *data,
- unsigned char *entropy, size_t length)
-{
- static bool ssl_seeded = FALSE;
- (void)data;
- if(!ssl_seeded) {
- ssl_seeded = TRUE;
- /* Initialize the seed if not already done. This call is not exactly thread
- * safe (and neither is the ssl_seeded check), but the worst effect of a
- * race condition is that some global resources will leak. */
- RNG_initialize();
- }
- get_random((int)length, entropy);
- return CURLE_OK;
-}
-
-static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
-{
- (void)info;
- return BACKEND->ssl;
-}
-
-const struct Curl_ssl Curl_ssl_axtls = {
- { CURLSSLBACKEND_AXTLS, "axtls" }, /* info */
- 0, /* no fancy stuff */
- sizeof(struct ssl_backend_data),
-
- /*
- * axTLS has no global init. Everything is done through SSL and SSL_CTX
- * structs stored in connectdata structure.
- */
- Curl_none_init, /* init */
- /* axTLS has no global cleanup. */
- Curl_none_cleanup, /* cleanup */
- Curl_axtls_version, /* version */
- Curl_axtls_check_cxn, /* check_cxn */
- Curl_axtls_shutdown, /* shutdown */
- Curl_none_data_pending, /* data_pending */
- Curl_axtls_random, /* random */
- Curl_none_cert_status_request, /* cert_status_request */
- Curl_axtls_connect, /* connect */
- Curl_axtls_connect_nonblocking, /* connect_nonblocking */
- Curl_axtls_get_internals, /* get_internals */
- Curl_axtls_close, /* close_one */
- Curl_none_close_all, /* close_all */
- Curl_axtls_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 */
-};
-
-#endif /* USE_AXTLS */
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c
index e10398ac3..44a2bdda6 100644
--- a/Utilities/cmcurl/lib/vtls/cyassl.c
+++ b/Utilities/cmcurl/lib/vtls/cyassl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -67,15 +67,6 @@ and that's a problem since options.h hasn't been included yet. */
#endif
#endif
-/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
- supported curve extension in options.h. Note ECC is enabled separately. */
-#ifndef HAVE_SUPPORTED_CURVES
-#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
- defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
-#define HAVE_SUPPORTED_CURVES
-#endif
-#endif
-
#include <limits.h>
#include "urldata.h"
@@ -88,6 +79,7 @@ and that's a problem since options.h hasn't been included yet. */
#include "strcase.h"
#include "x509asn1.h"
#include "curl_printf.h"
+#include "multiif.h"
#include <cyassl/openssl/ssl.h>
#include <cyassl/ssl.h>
@@ -151,7 +143,6 @@ static CURLcode
cyassl_connect_step1(struct connectdata *conn,
int sockindex)
{
- char error_buffer[CYASSL_MAX_ERROR_SZ];
char *ciphers;
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
@@ -364,16 +355,6 @@ cyassl_connect_step1(struct connectdata *conn,
}
#endif
-#ifdef HAVE_SUPPORTED_CURVES
- /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
- https://github.com/wolfSSL/wolfssl/issues/366
- The supported curves below are those also supported by OpenSSL 1.0.2 and
- in the same order. */
- CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */
- CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */
- CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x18); /* secp384r1 */
-#endif
-
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
CURLcode result = CURLE_OK;
@@ -438,6 +419,7 @@ cyassl_connect_step1(struct connectdata *conn,
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
+ char error_buffer[CYASSL_MAX_ERROR_SZ];
Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
ERR_error_string(SSL_get_error(BACKEND->handle, 0),
@@ -618,6 +600,8 @@ cyassl_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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else if(rc == SSL_ALPN_NOT_FOUND)
infof(data, "ALPN, server did not agree to a protocol\n");
@@ -777,13 +761,13 @@ static void Curl_cyassl_session_free(void *ptr)
static size_t Curl_cyassl_version(char *buffer, size_t size)
{
#if LIBCYASSL_VERSION_HEX >= 0x03006000
- return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
+ return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
#elif defined(WOLFSSL_VERSION)
- return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
+ return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
#elif defined(CYASSL_VERSION)
- return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
+ return msnprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
#else
- return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
+ return msnprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
#endif
}
@@ -794,6 +778,12 @@ static int Curl_cyassl_init(void)
}
+static void Curl_cyassl_cleanup(void)
+{
+ CyaSSL_Cleanup();
+}
+
+
static bool Curl_cyassl_data_pending(const struct connectdata* conn,
int connindex)
{
@@ -1004,7 +994,7 @@ const struct Curl_ssl Curl_ssl_cyassl = {
sizeof(struct ssl_backend_data),
Curl_cyassl_init, /* init */
- Curl_none_cleanup, /* cleanup */
+ Curl_cyassl_cleanup, /* cleanup */
Curl_cyassl_version, /* version */
Curl_none_check_cxn, /* check_cxn */
Curl_cyassl_shutdown, /* shutdown */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 8d1b3d6af..b93ff5d4f 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -734,12 +734,11 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
{
struct ssl_connect_data *connssl = &conn->ssl[num];
struct Curl_easy *data = conn->data;
- int buffsize;
int nread;
CURLcode cc = CURLE_RECV_ERROR;
if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
- buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
+ int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
buf, buffsize, &nread),
"gsk_secure_soc_read()", CURLE_RECV_ERROR);
@@ -806,7 +805,6 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
conn->host.name;
const char *sni;
unsigned int protoflags = 0;
- long timeout;
Qso_OverlappedIO_t commarea;
int sockpair[2];
static const int sobufsize = CURL_MAX_WRITE_SIZE;
@@ -914,7 +912,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
if(!result) {
/* Compute the handshake timeout. Since GSKit granularity is 1 second,
we round up the required value. */
- timeout = Curl_timeleft(data, NULL, TRUE);
+ long timeout = Curl_timeleft(data, NULL, TRUE);
if(timeout < 0)
result = CURLE_OPERATION_TIMEDOUT;
else
@@ -1021,14 +1019,13 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
Qso_OverlappedIO_t cstat;
- long timeout_ms;
struct timeval stmv;
CURLcode result;
/* Poll or wait for end of SSL asynchronous handshake. */
for(;;) {
- timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
+ long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0)
timeout_ms = 0;
stmv.tv_sec = timeout_ms / 1000;
@@ -1077,7 +1074,6 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
const char *cert = (const char *) NULL;
const char *certend;
const char *ptr;
- int i;
CURLcode result;
/* SSL handshake done: gather certificate info and verify host. */
@@ -1087,6 +1083,8 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
&cdev, &cdec),
"gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
CURLE_OK) {
+ int i;
+
infof(data, "Server certificate:\n");
p = cdev;
for(i = 0; i++ < cdec; p++)
@@ -1160,7 +1158,6 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
long timeout_ms;
- Qso_OverlappedIO_t cstat;
CURLcode result = CURLE_OK;
*done = connssl->state == ssl_connection_complete;
@@ -1262,7 +1259,6 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
- ssize_t nread;
int what;
int rc;
char buf[120];
@@ -1270,8 +1266,10 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
if(!BACKEND->handle)
return 0;
+#ifndef CURL_DISABLE_FTP
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
return 0;
+#endif
close_one(connssl, conn, sockindex);
rc = 0;
@@ -1279,6 +1277,8 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
SSL_SHUTDOWN_TIMEOUT);
for(;;) {
+ ssize_t nread;
+
if(what < 0) {
/* anything that gets here is fatally bad */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -1314,7 +1314,7 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
static size_t Curl_gskit_version(char *buffer, size_t size)
{
- return snprintf(buffer, size, "GSKit");
+ return msnprintf(buffer, size, "GSKit");
}
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 37662a748..8693cdce3 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -55,6 +55,7 @@
#include "strcase.h"
#include "warnless.h"
#include "x509asn1.h"
+#include "multiif.h"
#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
@@ -227,17 +228,17 @@ static void showtime(struct Curl_easy *data,
if(result)
return;
- snprintf(str,
- sizeof(str),
- "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
- text,
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
+ msnprintf(str,
+ sizeof(str),
+ "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
+ text,
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
infof(data, "%s\n", str);
}
#endif
@@ -285,11 +286,11 @@ static CURLcode handshake(struct connectdata *conn,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
gnutls_session_t session = BACKEND->session;
curl_socket_t sockfd = conn->sock[sockindex];
- time_t timeout_ms;
- int rc;
- int what;
for(;;) {
+ time_t timeout_ms;
+ int rc;
+
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, duringconnect);
@@ -302,7 +303,7 @@ static CURLcode handshake(struct connectdata *conn,
/* if ssl is expecting something, check if it's available. */
if(connssl->connecting_state == ssl_connect_2_reading
|| connssl->connecting_state == ssl_connect_2_writing) {
-
+ int what;
curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
curl_socket_t readfd = ssl_connect_2_reading ==
@@ -956,7 +957,6 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
gnutls_pubkey_t key = NULL;
/* Result is returned to caller */
- int ret = 0;
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
/* if a path wasn't specified, don't pin */
@@ -967,6 +967,8 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
return result;
do {
+ int ret;
+
/* Begin Gyrations to get the public key */
gnutls_pubkey_init(&key);
@@ -1110,7 +1112,7 @@ gtls_connect_step3(struct connectdata *conn,
"CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
"none",
SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\t server certificate verification FAILED\n");
@@ -1278,10 +1280,7 @@ gtls_connect_step3(struct connectdata *conn,
#define use_addr in_addr
#endif
unsigned char addrbuf[sizeof(struct use_addr)];
- unsigned char certaddr[sizeof(struct use_addr)];
- size_t addrlen = 0, certaddrlen;
- int i;
- int ret = 0;
+ size_t addrlen = 0;
if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
addrlen = 4;
@@ -1291,10 +1290,13 @@ gtls_connect_step3(struct connectdata *conn,
#endif
if(addrlen) {
+ unsigned char certaddr[sizeof(struct use_addr)];
+ int i;
+
for(i = 0; ; i++) {
- certaddrlen = sizeof(certaddr);
- ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
- &certaddrlen, NULL);
+ size_t certaddrlen = sizeof(certaddr);
+ int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
+ &certaddrlen, NULL);
/* If this happens, it wasn't an IP address. */
if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
continue;
@@ -1423,11 +1425,6 @@ gtls_connect_step3(struct connectdata *conn,
size = sizeof(certbuf);
gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
infof(data, "\t issuer: %s\n", certbuf);
-
- /* compression algorithm (if any) */
- ptr = gnutls_compression_get_name(gnutls_compression_get(session));
- /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
- infof(data, "\t compression: %s\n", ptr);
#endif
gnutls_x509_crt_deinit(x509_cert);
@@ -1454,6 +1451,9 @@ 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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -1466,8 +1466,6 @@ gtls_connect_step3(struct connectdata *conn,
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
detect that. */
- bool incache;
- void *ssl_sessionid;
void *connect_sessionid;
size_t connect_idsize = 0;
@@ -1476,6 +1474,9 @@ gtls_connect_step3(struct connectdata *conn,
connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
if(connect_sessionid) {
+ bool incache;
+ void *ssl_sessionid;
+
/* extract session ID to the allocated buffer */
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
@@ -1636,12 +1637,10 @@ static void Curl_gtls_close(struct connectdata *conn, int sockindex)
static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- ssize_t result;
int retval = 0;
struct Curl_easy *data = conn->data;
- bool done = FALSE;
- char buf[120];
+#ifndef CURL_DISABLE_FTP
/* This has only been tested on the proftpd server, and the mod_tls code
sends a close notify alert without waiting for a close notify alert in
response. Thus we wait for a close notify alert from the server, but
@@ -1649,8 +1648,13 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR);
+#endif
if(BACKEND->session) {
+ ssize_t result;
+ bool done = FALSE;
+ char buf[120];
+
while(!done) {
int what = SOCKET_READABLE(conn->sock[sockindex],
SSL_SHUTDOWN_TIMEOUT);
@@ -1748,7 +1752,7 @@ static void Curl_gtls_session_free(void *ptr)
static size_t Curl_gtls_version(char *buffer, size_t size)
{
- return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
+ return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
}
#ifndef USE_GNUTLS_NETTLE
@@ -1763,12 +1767,6 @@ static int Curl_gtls_seed(struct Curl_easy *data)
if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
data->set.str[STRING_SSL_EGDSOCKET]) {
-
- /* TODO: to a good job seeding the RNG
- This may involve the gcry_control function and these options:
- GCRYCTL_SET_RANDOM_SEED_FILE
- GCRYCTL_SET_RNDEGD_SOCKET
- */
ssl_seeded = TRUE;
}
return 0;
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index c5ed8872e..63d1f4c81 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -54,6 +54,7 @@
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
+#include "multiif.h"
#include "polarssl_threadlock.h"
/* The last 3 #include files should be in this order */
@@ -342,7 +343,8 @@ mbed_connect_step1(struct connectdata *conn,
if(SSL_SET_OPTION(key)) {
ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key),
SSL_SET_OPTION(key_passwd));
- if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA))
+ if(ret == 0 && !(mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA) ||
+ mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_ECKEY)))
ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
if(ret) {
@@ -373,7 +375,7 @@ mbed_connect_step1(struct connectdata *conn,
}
}
- infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
+ infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port);
mbedtls_ssl_config_init(&BACKEND->config);
@@ -539,13 +541,6 @@ mbed_connect_step2(struct connectdata *conn,
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#ifdef HAS_ALPN
- const char *next_protocol;
-#endif
-
- char errorbuf[128];
- errorbuf[0] = 0;
-
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
@@ -560,6 +555,8 @@ mbed_connect_step2(struct connectdata *conn,
return CURLE_OK;
}
else if(ret) {
+ char errorbuf[128];
+ errorbuf[0] = 0;
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
@@ -574,19 +571,21 @@ mbed_connect_step2(struct connectdata *conn,
ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl);
+ if(!SSL_CONN_CONFIG(verifyhost))
+ /* Ignore hostname errors if verifyhost is disabled */
+ ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
+
if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
- if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
+ else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
failf(data, "Cert verify failed: BADCERT_REVOKED");
- return CURLE_SSL_CACERT;
- }
- if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+ else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
- if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+ else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
return CURLE_PEER_FAILED_VERIFICATION;
@@ -662,7 +661,7 @@ mbed_connect_step2(struct connectdata *conn,
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
- next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl);
+ const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl);
if(next_protocol) {
infof(data, "ALPN, server accepted to use %s\n", next_protocol);
@@ -682,6 +681,8 @@ 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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -714,6 +715,8 @@ mbed_connect_step3(struct connectdata *conn,
ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
if(ret) {
+ if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
+ mbedtls_ssl_session_free(our_ssl_sessionid);
free(our_ssl_sessionid);
failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
@@ -727,6 +730,7 @@ mbed_connect_step3(struct connectdata *conn,
retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
Curl_ssl_sessionid_unlock(conn);
if(retcode) {
+ mbedtls_ssl_session_free(our_ssl_sessionid);
free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
return retcode;
@@ -811,9 +815,14 @@ static void Curl_mbedtls_session_free(void *ptr)
static size_t Curl_mbedtls_version(char *buffer, size_t size)
{
+#ifdef MBEDTLS_VERSION_C
+ /* if mbedtls_version_get_number() is available it is better */
unsigned int version = mbedtls_version_get_number();
- return snprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
- (version>>16)&0xff, (version>>8)&0xff);
+ return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
+ (version>>16)&0xff, (version>>8)&0xff);
+#else
+ return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
+#endif
}
static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c
index 6a2b67e63..718c282ee 100644
--- a/Utilities/cmcurl/lib/vtls/mesalink.c
+++ b/Utilities/cmcurl/lib/vtls/mesalink.c
@@ -5,8 +5,8 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * 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 - 2018, 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
@@ -268,7 +268,7 @@ mesalink_connect_step2(struct connectdata *conn, int sockindex)
char error_buffer[MESALINK_MAX_ERROR_SZ];
int detail = SSL_get_error(BACKEND->handle, ret);
- if(SSL_ERROR_WANT_CONNECT == detail) {
+ if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
@@ -424,7 +424,7 @@ mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
static size_t
Curl_mesalink_version(char *buffer, size_t size)
{
- return snprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
+ return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
}
static int
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index a3d3e58bb..491def106 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -38,6 +38,7 @@
#include "select.h"
#include "vtls.h"
#include "llist.h"
+#include "multiif.h"
#include "curl_printf.h"
#include "nssg.h"
#include <nspr.h>
@@ -246,6 +247,32 @@ static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
}
+static char *nss_sslver_to_name(PRUint16 nssver)
+{
+ switch(nssver) {
+ case SSL_LIBRARY_VERSION_2:
+ return strdup("SSLv2");
+ case SSL_LIBRARY_VERSION_3_0:
+ return strdup("SSLv3");
+ case SSL_LIBRARY_VERSION_TLS_1_0:
+ return strdup("TLSv1.0");
+#ifdef SSL_LIBRARY_VERSION_TLS_1_1
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ return strdup("TLSv1.1");
+#endif
+#ifdef SSL_LIBRARY_VERSION_TLS_1_2
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ return strdup("TLSv1.2");
+#endif
+#ifdef SSL_LIBRARY_VERSION_TLS_1_3
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ return strdup("TLSv1.3");
+#endif
+ default:
+ return curl_maprintf("0x%04x", nssver);
+ }
+}
+
static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
char *cipher_list)
{
@@ -351,7 +378,7 @@ static int is_file(const char *filename)
return 0;
if(stat(filename, &st) == 0)
- if(S_ISREG(st.st_mode))
+ if(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
return 1;
return 0;
@@ -817,6 +844,8 @@ 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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
@@ -1279,6 +1308,8 @@ static void nss_unload_module(SECMODModule **pmod)
static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
{
NSSInitParameters initparams;
+ PRErrorCode err;
+ const char *err_name;
if(nss_context != NULL)
return CURLE_OK;
@@ -1299,7 +1330,9 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
if(nss_context != NULL)
return CURLE_OK;
- infof(data, "Unable to initialize NSS database\n");
+ err = PR_GetError();
+ err_name = nss_error_to_name(err);
+ infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name);
}
infof(data, "Initializing NSS with certpath: none\n");
@@ -1309,7 +1342,9 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
if(nss_context != NULL)
return CURLE_OK;
- infof(data, "Unable to initialize NSS\n");
+ err = PR_GetError();
+ err_name = nss_error_to_name(err);
+ failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
return CURLE_SSL_CACERT_BADFILE;
}
@@ -1638,17 +1673,6 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
{
switch(version) {
- case CURL_SSLVERSION_TLSv1:
- /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */
-#ifdef SSL_LIBRARY_VERSION_TLS_1_2
- *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
-#elif defined SSL_LIBRARY_VERSION_TLS_1_1
- *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
-#else
- *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
-#endif
- return CURLE_OK;
-
case CURL_SSLVERSION_SSLv2:
*nssver = SSL_LIBRARY_VERSION_2;
return CURLE_OK;
@@ -1709,10 +1733,8 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
}
switch(min) {
- case CURL_SSLVERSION_DEFAULT:
- break;
case CURL_SSLVERSION_TLSv1:
- sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ case CURL_SSLVERSION_DEFAULT:
break;
default:
result = nss_sslver_from_curl(&sslver->min, min);
@@ -1789,10 +1811,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result;
bool second_layer = FALSE;
+ SSLVersionRange sslver_supported;
SSLVersionRange sslver = {
SSL_LIBRARY_VERSION_TLS_1_0, /* min */
- SSL_LIBRARY_VERSION_TLS_1_0 /* max */
+#ifdef SSL_LIBRARY_VERSION_TLS_1_3
+ SSL_LIBRARY_VERSION_TLS_1_3 /* max */
+#elif defined SSL_LIBRARY_VERSION_TLS_1_2
+ SSL_LIBRARY_VERSION_TLS_1_2
+#elif defined SSL_LIBRARY_VERSION_TLS_1_1
+ SSL_LIBRARY_VERSION_TLS_1_1
+#else
+ SSL_LIBRARY_VERSION_TLS_1_0
+#endif
};
BACKEND->data = data;
@@ -1800,7 +1831,6 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* list of all NSS objects we need to destroy in Curl_nss_close() */
Curl_llist_init(&BACKEND->obj_list, nss_destroy_object);
- /* FIXME. NSS doesn't support multiple databases open at the same time. */
PR_Lock(nss_initlock);
result = nss_init(conn->data);
if(result) {
@@ -1841,6 +1871,20 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* enable/disable the requested SSL version(s) */
if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
goto error;
+ if(SSL_VersionRangeGetSupported(ssl_variant_stream,
+ &sslver_supported) != SECSuccess)
+ goto error;
+ if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
+ char *sslver_req_str, *sslver_supp_str;
+ sslver_req_str = nss_sslver_to_name(sslver.max);
+ sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
+ if(sslver_req_str && sslver_supp_str)
+ infof(data, "Falling back from %s to max supported SSL version (%s)\n",
+ sslver_req_str, sslver_supp_str);
+ free(sslver_req_str);
+ free(sslver_supp_str);
+ sslver.max = sslver_supported.max;
+ }
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
goto error;
@@ -2090,7 +2134,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
result = CURLE_PEER_FAILED_VERIFICATION;
else if(*certverifyresult != 0)
- result = CURLE_SSL_CACERT;
+ result = CURLE_PEER_FAILED_VERIFICATION;
goto error;
}
@@ -2164,7 +2208,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
if(!blocking)
/* CURLE_AGAIN in non-blocking mode is not an error */
return CURLE_OK;
- /* fall through */
+ /* FALLTHROUGH */
default:
return result;
}
@@ -2279,7 +2323,7 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */
static size_t Curl_nss_version(char *buffer, size_t size)
{
- return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
+ return msnprintf(buffer, size, "NSS/%s", NSS_VERSION);
}
/* data might be NULL */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 4c5e8c19c..85e9be616 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -48,6 +48,7 @@
#include "vtls.h"
#include "strcase.h"
#include "hostcheck.h"
+#include "multiif.h"
#include "curl_printf.h"
#include <openssl/ssl.h>
#include <openssl/rand.h>
@@ -65,11 +66,15 @@
#include <openssl/buffer.h>
#include <openssl/pkcs12.h>
+#ifdef USE_AMISSL
+#include "amigaos.h"
+#endif
+
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && /* 0.9.8 or later */ \
+#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \
!defined(OPENSSL_NO_ENGINE)
#define USE_OPENSSL_ENGINE
#include <openssl/engine.h>
@@ -82,6 +87,13 @@
#include "curl_memory.h"
#include "memdebug.h"
+/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS
+ renegotiations when built with BoringSSL. Renegotiating is non-compliant
+ with HTTP/2 and "an extremely dangerous protocol feature". Beware.
+
+#define ALLOW_RENEG 1
+ */
+
#ifndef OPENSSL_VERSION_NUMBER
#error "OPENSSL_VERSION_NUMBER not defined"
#endif
@@ -384,6 +396,31 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
return buf;
}
+/* Return an extra data index for the connection data.
+ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
+ */
+static int ossl_get_ssl_conn_index(void)
+{
+ static int ssl_ex_data_conn_index = -1;
+ if(ssl_ex_data_conn_index < 0) {
+ ssl_ex_data_conn_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ }
+ return ssl_ex_data_conn_index;
+}
+
+/* Return an extra data index for the sockindex.
+ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
+ */
+static int ossl_get_ssl_sockindex_index(void)
+{
+ static int ssl_ex_data_sockindex_index = -1;
+ if(ssl_ex_data_sockindex_index < 0) {
+ ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+ }
+ return ssl_ex_data_sockindex_index;
+}
+
static int passwd_callback(char *buf, int num, int encrypting,
void *global_passwd)
{
@@ -788,8 +825,11 @@ int cert_stuff(struct connectdata *conn,
fail:
EVP_PKEY_free(pri);
X509_free(x509);
+#ifdef USE_AMISSL
+ sk_X509_pop_free(ca, Curl_amiga_X509_free);
+#else
sk_X509_pop_free(ca, X509_free);
-
+#endif
if(!cert_done)
return 0; /* failure! */
break;
@@ -799,15 +839,15 @@ int cert_stuff(struct connectdata *conn,
return 0;
}
- file_type = do_file_type(key_type);
+ if(!key_file)
+ key_file = cert_file;
+ else
+ file_type = do_file_type(key_type);
switch(file_type) {
case SSL_FILETYPE_PEM:
if(cert_done)
break;
- if(!key_file)
- /* cert & key can only be in PEM case in the same file */
- key_file = cert_file;
/* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
@@ -1035,6 +1075,10 @@ static int Curl_ossl_init(void)
}
#endif
+ /* Initialize the extra data indexes */
+ if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0)
+ return 0;
+
return 1;
}
@@ -1049,7 +1093,7 @@ static void Curl_ossl_cleanup(void)
/* Free ciphers and digests lists */
EVP_cleanup();
-#ifdef HAVE_ENGINE_CLEANUP
+#ifdef USE_OPENSSL_ENGINE
/* Free engine list */
ENGINE_cleanup();
#endif
@@ -1264,6 +1308,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
int err;
bool done = FALSE;
+#ifndef CURL_DISABLE_FTP
/* This has only been tested on the proftpd server, and the mod_tls code
sends a close notify alert without waiting for a close notify alert in
response. Thus we wait for a close notify alert from the server, but
@@ -1271,6 +1316,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
(void)SSL_shutdown(BACKEND->handle);
+#endif
if(BACKEND->handle) {
buffsize = (int)sizeof(buf);
@@ -1656,6 +1702,7 @@ static CURLcode verifystatus(struct connectdata *conn,
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;
@@ -1665,14 +1712,14 @@ static CURLcode verifystatus(struct connectdata *conn,
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p);
+ long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
- if(!p) {
+ if(!status) {
failf(data, "No OCSP response received");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
-
+ p = status;
rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
if(!rsp) {
failf(data, "Invalid OCSP response");
@@ -1867,15 +1914,8 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
return "Unknown";
}
-static const char *tls_rt_type(int type, const void *buf, size_t buflen)
+static const char *tls_rt_type(int type)
{
- (void)buf;
- (void)buflen;
-#ifdef SSL3_RT_INNER_CONTENT_TYPE
- if(type == SSL3_RT_INNER_CONTENT_TYPE && buf && buflen >= 1)
- type = *(unsigned char *)buf;
-#endif
-
switch(type) {
#ifdef SSL3_RT_HEADER
case SSL3_RT_HEADER:
@@ -1945,12 +1985,20 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
case 0:
break;
default:
- snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
+ msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
verstr = unknown;
break;
}
- if(ssl_ver) {
+ /* Log progress for interesting records only (like Handshake or Alert), skip
+ * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0).
+ * For TLS 1.3, skip notification of the decrypted inner Content Type.
+ */
+ if(ssl_ver
+#ifdef SSL3_RT_INNER_CONTENT_TYPE
+ && content_type != SSL3_RT_INNER_CONTENT_TYPE
+#endif
+ ) {
const char *msg_name, *tls_rt_name;
char ssl_buf[1024];
int msg_type, txt_len;
@@ -1964,17 +2012,10 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
* is at 'buf[0]'.
*/
if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
- tls_rt_name = tls_rt_type(content_type, buf, len);
+ tls_rt_name = tls_rt_type(content_type);
else
tls_rt_name = "";
-#ifdef SSL3_RT_INNER_CONTENT_TYPE
- if(content_type == SSL3_RT_INNER_CONTENT_TYPE) {
- msg_type = 0;
- msg_name = "[no content]";
- }
- else
-#endif
if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
msg_type = *(char *)buf;
msg_name = "Change cipher spec";
@@ -1988,9 +2029,9 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
msg_name = ssl_msg_type(ssl_ver, msg_type);
}
- txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
- verstr, direction?"OUT":"IN",
- tls_rt_name, msg_name, msg_type);
+ txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
+ verstr, direction?"OUT":"IN",
+ tls_rt_name, msg_name, msg_type);
if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
}
@@ -2137,6 +2178,7 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
}
#else
(void)sockindex;
+ (void)ctx_options;
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
#endif
@@ -2189,6 +2231,62 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
return CURLE_OK;
}
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+{
+ int res = 0;
+ struct connectdata *conn;
+ struct Curl_easy *data;
+ int sockindex;
+ curl_socket_t *sockindex_ptr;
+ int connectdata_idx = ossl_get_ssl_conn_index();
+ int sockindex_idx = ossl_get_ssl_sockindex_index();
+
+ if(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;
+
+ /* The sockindex has been stored as a pointer to an array element */
+ sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
+ sockindex = (int)(sockindex_ptr - conn->sock);
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ void *old_ssl_sessionid = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ incache = !(Curl_ssl_getsessionid(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);
+ incache = FALSE;
+ }
+ }
+
+ if(!incache) {
+ if(!Curl_ssl_addsessionid(conn, ssl_sessionid,
+ 0 /* unknown size */, sockindex)) {
+ /* the session has been put into the session cache */
+ res = 1;
+ }
+ else
+ failf(data, "failed to store ssl session");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ return res;
+}
+
static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
{
CURLcode result = CURLE_OK;
@@ -2585,6 +2683,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#endif
+ /* Enable the session cache because it's a prerequisite for the "new session"
+ * callback. Use the "external storage" mode to avoid that OpenSSL creates
+ * an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(BACKEND->ctx,
+ SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(BACKEND->ctx, ossl_new_session_cb);
+
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
@@ -2610,6 +2716,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
+#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG)
+ SSL_set_renegotiate_mode(BACKEND->handle, ssl_renegotiate_freely);
+#endif
+
SSL_set_connect_state(BACKEND->handle);
BACKEND->server_cert = 0x0;
@@ -2627,6 +2737,15 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
/* Check if there's a cached ID we can/should use here! */
if(SSL_SET_OPTION(primary.sessionid)) {
void *ssl_sessionid = NULL;
+ int connectdata_idx = ossl_get_ssl_conn_index();
+ int sockindex_idx = ossl_get_ssl_sockindex_index();
+
+ if(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, 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)) {
@@ -2699,6 +2818,12 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
+#ifdef SSL_ERROR_WANT_ASYNC
+ if(SSL_ERROR_WANT_ASYNC == detail) {
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+ }
+#endif
else {
/* untreated error */
unsigned long errdetail;
@@ -2721,14 +2846,14 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
if((lib == ERR_LIB_SSL) &&
(reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
- result = CURLE_SSL_CACERT;
+ result = CURLE_PEER_FAILED_VERIFICATION;
lerr = SSL_get_verify_result(BACKEND->handle);
if(lerr != X509_V_OK) {
*certverifyresult = lerr;
- snprintf(error_buffer, sizeof(error_buffer),
- "SSL certificate problem: %s",
- X509_verify_cert_error_string(lerr));
+ msnprintf(error_buffer, sizeof(error_buffer),
+ "SSL certificate problem: %s",
+ X509_verify_cert_error_string(lerr));
}
else
/* strcpy() is fine here as long as the string fits within
@@ -2795,6 +2920,9 @@ 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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -2839,7 +2967,7 @@ static void pubkey_show(struct Curl_easy *data,
char *ptr;
char namebuf[32];
- snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+ msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
if(bn)
BN_print(mem, bn);
@@ -2900,8 +3028,8 @@ static int X509V3_ext(struct Curl_easy *data,
while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
j++;
if(j<(size_t)biomem->length)
- ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
- biomem->data[j]);
+ ptr += msnprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
+ biomem->data[j]);
}
Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
@@ -3101,11 +3229,6 @@ static CURLcode get_cert_chain(struct connectdata *conn,
#endif
break;
}
-#if 0
- case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
- /* left TODO */
- break;
-#endif
}
EVP_PKEY_free(pubkey);
}
@@ -3214,20 +3337,8 @@ static CURLcode servercert(struct connectdata *conn,
/* we've been asked to gather certificate info! */
(void)get_cert_chain(conn, connssl);
- fp = BIO_new(BIO_s_file());
- if(fp == NULL) {
- failf(data,
- "BIO_new return NULL, " OSSL_PACKAGE
- " error %s",
- ossl_strerror(ERR_get_error(), error_buffer,
- sizeof(error_buffer)) );
- BIO_free(mem);
- return CURLE_OUT_OF_MEMORY;
- }
-
BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
if(!BACKEND->server_cert) {
- BIO_free(fp);
BIO_free(mem);
if(!strict)
return CURLE_OK;
@@ -3262,7 +3373,6 @@ static CURLcode servercert(struct connectdata *conn,
if(SSL_CONN_CONFIG(verifyhost)) {
result = verifyhost(conn, BACKEND->server_cert);
if(result) {
- BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return result;
@@ -3284,6 +3394,18 @@ static CURLcode servercert(struct connectdata *conn,
/* e.g. match issuer name with provided issuer certificate */
if(SSL_SET_OPTION(issuercert)) {
+ fp = BIO_new(BIO_s_file());
+ if(fp == NULL) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
@@ -3319,6 +3441,7 @@ static CURLcode servercert(struct connectdata *conn,
infof(data, " SSL certificate issuer check ok (%s)\n",
SSL_SET_OPTION(issuercert));
+ BIO_free(fp);
X509_free(issuer);
}
@@ -3347,7 +3470,6 @@ static CURLcode servercert(struct connectdata *conn,
if(SSL_CONN_CONFIG(verifystatus)) {
result = verifystatus(conn, connssl);
if(result) {
- BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
return result;
@@ -3367,7 +3489,6 @@ static CURLcode servercert(struct connectdata *conn,
failf(data, "SSL: public key does not match pinned public key!");
}
- BIO_free(fp);
X509_free(BACKEND->server_cert);
BACKEND->server_cert = NULL;
connssl->connecting_state = ssl_connect_done;
@@ -3378,52 +3499,10 @@ static CURLcode servercert(struct connectdata *conn,
static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
{
CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(SSL_SET_OPTION(primary.sessionid)) {
- bool incache;
- SSL_SESSION *our_ssl_sessionid;
- void *old_ssl_sessionid = NULL;
-
- our_ssl_sessionid = SSL_get1_session(BACKEND->handle);
-
- /* SSL_get1_session() will increment the reference count and the session
- will stay in memory until explicitly freed with SSL_SESSION_free(3),
- regardless of its state. */
-
- Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(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);
- incache = FALSE;
- }
- }
-
- if(!incache) {
- result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */, sockindex);
- if(result) {
- Curl_ssl_sessionid_unlock(conn);
- failf(data, "failed to store ssl session");
- return result;
- }
- }
- else {
- /* Session was incache, so refcount already incremented earlier.
- * Avoid further increments with each SSL_get1_session() call.
- * This does not free the session as refcount remains > 0
- */
- SSL_SESSION_free(our_ssl_sessionid);
- }
- Curl_ssl_sessionid_unlock(conn);
- }
-
/*
* We check certificates to authenticate the server; otherwise we risk
* man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
@@ -3678,7 +3757,10 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
+ break;
case SSL_ERROR_ZERO_RETURN: /* no more data */
+ /* close_notify alert */
+ connclose(conn, "TLS close_notify");
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
@@ -3709,8 +3791,13 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
static size_t Curl_ossl_version(char *buffer, size_t size)
{
#ifdef OPENSSL_IS_BORINGSSL
- return snprintf(buffer, size, OSSL_PACKAGE);
-#else /* OPENSSL_IS_BORINGSSL */
+ return msnprintf(buffer, size, OSSL_PACKAGE);
+#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING)
+ return msnprintf(buffer, size, "%s/%s",
+ OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING));
+#else
+ /* not BoringSSL and not using OpenSSL_version */
+
char sub[3];
unsigned long ssleay_value;
sub[2]='\0';
@@ -3736,12 +3823,16 @@ static size_t Curl_ossl_version(char *buffer, size_t size)
sub[0]='\0';
}
- return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
- OSSL_PACKAGE,
- (ssleay_value>>28)&0xf,
- (ssleay_value>>20)&0xff,
- (ssleay_value>>12)&0xff,
- sub);
+ return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s"
+#ifdef OPENSSL_FIPS
+ "-fips"
+#endif
+ ,
+ OSSL_PACKAGE,
+ (ssleay_value>>28)&0xf,
+ (ssleay_value>>20)&0xff,
+ (ssleay_value>>12)&0xff,
+ sub);
#endif /* OPENSSL_IS_BORINGSSL */
}
diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c
index 27af0ccf3..7ea26b442 100644
--- a/Utilities/cmcurl/lib/vtls/polarssl.c
+++ b/Utilities/cmcurl/lib/vtls/polarssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* This software is licensed as described in the file COPYING, which
@@ -55,6 +55,7 @@
#include "select.h"
#include "strcase.h"
#include "polarssl_threadlock.h"
+#include "multiif.h"
#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
@@ -497,7 +498,7 @@ polarssl_connect_step2(struct connectdata *conn,
if(ret & BADCERT_REVOKED) {
failf(data, "Cert verify failed: BADCERT_REVOKED");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
}
if(ret & BADCERT_CN_MISMATCH)
@@ -593,6 +594,8 @@ polarssl_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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -716,9 +719,9 @@ static void Curl_polarssl_session_free(void *ptr)
static size_t Curl_polarssl_version(char *buffer, size_t size)
{
unsigned int version = version_get_number();
- return snprintf(buffer, size, "%s/%d.%d.%d",
- version >= 0x01030A00?"mbedTLS":"PolarSSL",
- version>>24, (version>>16)&0xff, (version>>8)&0xff);
+ return msnprintf(buffer, size, "%s/%d.%d.%d",
+ version >= 0x01030A00?"mbedTLS":"PolarSSL",
+ version>>24, (version>>16)&0xff, (version>>8)&0xff);
}
static CURLcode
@@ -908,9 +911,7 @@ const struct Curl_ssl Curl_ssl_polarssl = {
Curl_none_check_cxn, /* check_cxn */
Curl_none_shutdown, /* shutdown */
Curl_polarssl_data_pending, /* data_pending */
- /* This might cause libcurl to use a weeker random!
- * TODO: use Polarssl's CTR-DRBG or HMAC-DRBG
- */
+ /* This might cause libcurl to use a weeker random! */
Curl_none_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
Curl_polarssl_connect, /* connect */
diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c
index dd5fbd7ec..27c94b11e 100644
--- a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c
+++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c
@@ -23,16 +23,15 @@
#include "curl_setup.h"
#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \
- (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32))
-
-#if defined(USE_THREADS_POSIX)
-# ifdef HAVE_PTHREAD_H
-# include <pthread.h>
-# endif
-#elif defined(USE_THREADS_WIN32)
-# ifdef HAVE_PROCESS_H
-# include <process.h>
-# endif
+ ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
+ (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)))
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+# include <pthread.h>
+# define POLARSSL_MUTEX_T pthread_mutex_t
+#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+# include <process.h>
+# define POLARSSL_MUTEX_T HANDLE
#endif
#include "polarssl_threadlock.h"
@@ -50,25 +49,23 @@ static POLARSSL_MUTEX_T *mutex_buf = NULL;
int Curl_polarsslthreadlock_thread_setup(void)
{
int i;
- int ret;
mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1);
if(!mutex_buf)
return 0; /* error, no number of threads defined */
-#ifdef HAVE_PTHREAD_H
for(i = 0; i < NUMT; i++) {
+ int ret;
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
ret = pthread_mutex_init(&mutex_buf[i], NULL);
if(ret)
return 0; /* pthread_mutex_init failed */
- }
-#elif defined(HAVE_PROCESS_H)
- for(i = 0; i < NUMT; i++) {
+#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
mutex_buf[i] = CreateMutex(0, FALSE, 0);
if(mutex_buf[i] == 0)
return 0; /* CreateMutex failed */
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
}
-#endif /* HAVE_PTHREAD_H */
return 1; /* OK */
}
@@ -76,24 +73,22 @@ int Curl_polarsslthreadlock_thread_setup(void)
int Curl_polarsslthreadlock_thread_cleanup(void)
{
int i;
- int ret;
if(!mutex_buf)
return 0; /* error, no threads locks defined */
-#ifdef HAVE_PTHREAD_H
for(i = 0; i < NUMT; i++) {
+ int ret;
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
ret = pthread_mutex_destroy(&mutex_buf[i]);
if(ret)
return 0; /* pthread_mutex_destroy failed */
- }
-#elif defined(HAVE_PROCESS_H)
- for(i = 0; i < NUMT; i++) {
+#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
ret = CloseHandle(mutex_buf[i]);
if(!ret)
return 0; /* CloseHandle failed */
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
}
-#endif /* HAVE_PTHREAD_H */
free(mutex_buf);
mutex_buf = NULL;
@@ -102,51 +97,47 @@ int Curl_polarsslthreadlock_thread_cleanup(void)
int Curl_polarsslthreadlock_lock_function(int n)
{
- int ret;
-#ifdef HAVE_PTHREAD_H
if(n < NUMT) {
+ int ret;
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
ret = pthread_mutex_lock(&mutex_buf[n]);
if(ret) {
DEBUGF(fprintf(stderr,
"Error: polarsslthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
- }
-#elif defined(HAVE_PROCESS_H)
- if(n < NUMT) {
+#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0);
if(ret) {
DEBUGF(fprintf(stderr,
"Error: polarsslthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
}
-#endif /* HAVE_PTHREAD_H */
return 1; /* OK */
}
int Curl_polarsslthreadlock_unlock_function(int n)
{
- int ret;
-#ifdef HAVE_PTHREAD_H
if(n < NUMT) {
+ int ret;
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
ret = pthread_mutex_unlock(&mutex_buf[n]);
if(ret) {
DEBUGF(fprintf(stderr,
"Error: polarsslthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_unlock failed */
}
- }
-#elif defined(HAVE_PROCESS_H)
- if(n < NUMT) {
+#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
ret = ReleaseMutex(mutex_buf[n]);
if(!ret) {
DEBUGF(fprintf(stderr,
"Error: polarsslthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
}
-#endif /* HAVE_PTHREAD_H */
return 1; /* OK */
}
diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h
index dda5359b8..122647528 100644
--- a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h
+++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h
@@ -26,13 +26,8 @@
#if (defined USE_POLARSSL) || (defined USE_MBEDTLS)
-#if defined(USE_THREADS_POSIX)
-# define POLARSSL_MUTEX_T pthread_mutex_t
-#elif defined(USE_THREADS_WIN32)
-# define POLARSSL_MUTEX_T HANDLE
-#endif
-
-#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
+ (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))
int Curl_polarsslthreadlock_thread_setup(void);
int Curl_polarsslthreadlock_thread_cleanup(void);
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index e4426924b..0f6f734fd 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -23,9 +23,8 @@
***************************************************************************/
/*
- * Source file for all SChannel-specific code for the TLS/SSL layer. No code
+ * Source file for all Schannel-specific code for the TLS/SSL layer. No code
* but vtls.c should ever call or use these functions.
- *
*/
/*
@@ -59,6 +58,7 @@
#include "warnless.h"
#include "x509asn1.h"
#include "curl_printf.h"
+#include "multiif.h"
#include "system_win32.h"
/* The last #include file should be: */
@@ -196,7 +196,7 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_3:
- failf(data, "Schannel: TLS 1.3 is not yet supported");
+ failf(data, "schannel: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -325,6 +325,9 @@ get_alg_id_by_name(char *name)
#ifdef CALG_ECDSA
CIPHEROPTION(CALG_ECDSA);
#endif
+#ifdef CALG_ECDH_EPHEM
+ CIPHEROPTION(CALG_ECDH_EPHEM);
+#endif
return 0;
}
@@ -357,6 +360,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
TCHAR **thumbprint)
{
TCHAR *sep;
+ TCHAR *store_path_start;
size_t store_name_len;
sep = _tcschr(path, TEXT('\\'));
@@ -387,13 +391,17 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
else
return CURLE_SSL_CERTPROBLEM;
- *store_path = sep + 1;
+ store_path_start = sep + 1;
- sep = _tcschr(*store_path, TEXT('\\'));
+ sep = _tcschr(store_path_start, TEXT('\\'));
if(sep == NULL)
return CURLE_SSL_CERTPROBLEM;
- *sep = 0;
+ *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)
@@ -429,14 +437,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
- hostname, conn->remote_port);
+ DEBUGF(infof(data,
+ "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
+ hostname, conn->remote_port));
if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
- /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
+ /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
algorithms that may not be supported by all servers. */
- infof(data, "schannel: WinSSL version is old and may not be able to "
+ infof(data, "schannel: Windows version is old and may not be able to "
"connect to some servers due to lack of SNI, algorithms, etc.\n");
}
@@ -490,12 +499,13 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
BACKEND->cred = old_cred;
- infof(data, "schannel: re-using existing credential handle\n");
+ DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
/* increment the reference counter of the credential/session handle */
BACKEND->cred->refcount++;
- infof(data, "schannel: incremented credential handle refcount = %d\n",
- BACKEND->cred->refcount);
+ DEBUGF(infof(data,
+ "schannel: incremented credential handle refcount = %d\n",
+ BACKEND->cred->refcount));
}
Curl_ssl_sessionid_unlock(conn);
}
@@ -513,31 +523,32 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#endif
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
- /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
if(data->set.ssl.no_revoke) {
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
- infof(data, "schannel: disabled server certificate revocation "
- "checks\n");
+ DEBUGF(infof(data, "schannel: disabled server certificate revocation "
+ "checks\n"));
}
else {
schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
- infof(data, "schannel: checking server certificate revocation\n");
+ DEBUGF(infof(data,
+ "schannel: checking server certificate revocation\n"));
}
}
else {
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
- infof(data, "schannel: disabled server certificate revocation checks\n");
+ DEBUGF(infof(data,
+ "schannel: disabled server cert revocation checks\n"));
}
if(!conn->ssl_config.verifyhost) {
schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
- infof(data, "schannel: verifyhost setting prevents Schannel from "
- "comparing the supplied target name with the subject "
- "names in server certificates.\n");
+ DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
+ "comparing the supplied target name with the subject "
+ "names in server certificates.\n"));
}
switch(conn->ssl_config.version) {
@@ -609,9 +620,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
failf(data, "schannel: Failed to open cert store %x %s, "
"last error is %x",
cert_store_name, cert_store_path, GetLastError());
+ free(cert_store_path);
Curl_unicodefree(cert_path);
return CURLE_SSL_CERTPROBLEM;
}
+ free(cert_store_path);
cert_thumbprint.pbData = cert_thumbprint_data;
cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
@@ -674,8 +687,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
CertFreeCertificateContext(client_certs[0]);
if(sspi_status != SEC_E_OK) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: AcquireCredentialsHandle failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
Curl_safefree(BACKEND->cred);
switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY:
@@ -790,15 +804,16 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
Curl_unicodefree(host_name);
if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+ char buffer[STRERROR_LEN];
Curl_safefree(BACKEND->ctxt);
switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY:
failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_OUT_OF_MEMORY;
case SEC_E_WRONG_PRINCIPAL:
failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_PEER_FAILED_VERIFICATION;
/*
case SEC_E_INVALID_HANDLE:
@@ -813,13 +828,13 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
*/
default:
failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
}
- infof(data, "schannel: sending initial handshake data: "
- "sending %lu bytes...\n", outbuf.cbBuffer);
+ DEBUGF(infof(data, "schannel: sending initial handshake data: "
+ "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,
@@ -831,8 +846,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "schannel: sent initial handshake data: "
- "sent %zd bytes\n", written);
+ DEBUGF(infof(data, "schannel: sent initial handshake data: "
+ "sent %zd bytes\n", written));
BACKEND->recv_unrecoverable_err = CURLE_OK;
BACKEND->recv_sspi_close_notify = false;
@@ -853,13 +868,11 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
unsigned char *reallocated_buffer;
- size_t reallocated_length;
SecBuffer outbuf[3];
SecBufferDesc outbuf_desc;
SecBuffer inbuf[2];
SecBufferDesc inbuf_desc;
SECURITY_STATUS sspi_status = SEC_E_OK;
- TCHAR *host_name;
CURLcode result;
bool doread;
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
@@ -868,8 +881,9 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
- hostname, conn->remote_port);
+ DEBUGF(infof(data,
+ "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
+ hostname, conn->remote_port));
if(!BACKEND->cred || !BACKEND->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -901,7 +915,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
if(BACKEND->encdata_length - BACKEND->encdata_offset <
CURL_SCHANNEL_BUFFER_FREE_SIZE) {
/* increase internal encrypted data buffer */
- reallocated_length = BACKEND->encdata_offset +
+ size_t reallocated_length = BACKEND->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE;
reallocated_buffer = realloc(BACKEND->encdata_buffer,
reallocated_length);
@@ -917,6 +931,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
for(;;) {
+ TCHAR *host_name;
if(doread) {
/* read encrypted handshake data from socket */
result = Curl_read_plain(conn->sock[sockindex],
@@ -928,8 +943,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
connssl->connecting_state = ssl_connect_2_reading;
- infof(data, "schannel: failed to receive handshake, "
- "need more data\n");
+ DEBUGF(infof(data, "schannel: failed to receive handshake, "
+ "need more data\n"));
return CURLE_OK;
}
else if((result != CURLE_OK) || (nread == 0)) {
@@ -941,11 +956,12 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* increase encrypted data buffer offset */
BACKEND->encdata_offset += nread;
BACKEND->encdata_is_incomplete = false;
- infof(data, "schannel: encrypted data got %zd\n", nread);
+ DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
}
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- BACKEND->encdata_offset, BACKEND->encdata_length);
+ DEBUGF(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu\n",
+ BACKEND->encdata_offset, BACKEND->encdata_length));
/* setup input buffers */
InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
@@ -988,7 +1004,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
BACKEND->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading;
- infof(data, "schannel: received incomplete message, need more data\n");
+ DEBUGF(infof(data,
+ "schannel: received incomplete message, need more data\n"));
return CURLE_OK;
}
@@ -999,7 +1016,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
!(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
connssl->connecting_state = ssl_connect_2_writing;
- infof(data, "schannel: a client certificate has been requested\n");
+ DEBUGF(infof(data,
+ "schannel: a client certificate has been requested\n"));
return CURLE_OK;
}
@@ -1008,8 +1026,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
for(i = 0; i < 3; i++) {
/* search for handshake tokens that need to be send */
if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
- infof(data, "schannel: sending next handshake data: "
- "sending %lu bytes...\n", outbuf[i].cbBuffer);
+ DEBUGF(infof(data, "schannel: sending next handshake data: "
+ "sending %lu bytes...\n", outbuf[i].cbBuffer));
/* send handshake token to server */
result = Curl_write_plain(conn, conn->sock[sockindex],
@@ -1030,14 +1048,15 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
}
else {
+ char buffer[STRERROR_LEN];
switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY:
failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_OUT_OF_MEMORY;
case SEC_E_WRONG_PRINCIPAL:
failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_PEER_FAILED_VERIFICATION;
/*
case SEC_E_INVALID_HANDLE:
@@ -1052,14 +1071,15 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
*/
default:
failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
}
/* check if there was additional remaining encrypted data */
if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
- infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
+ DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+ inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
1) If we're renegotiating a connection and the handshake is already
@@ -1098,7 +1118,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* check if the handshake is complete */
if(sspi_status == SEC_E_OK) {
connssl->connecting_state = ssl_connect_3;
- infof(data, "schannel: SSL/TLS handshake complete\n");
+ DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
}
pubkey_ptr = SSL_IS_PROXY() ?
@@ -1114,13 +1134,68 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
#ifdef HAS_MANUAL_VERIFY_API
if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
- return verify_certificate(conn, sockindex);
+ return Curl_verify_certificate(conn, sockindex);
}
#endif
return CURLE_OK;
}
+static bool
+valid_cert_encoding(const CERT_CONTEXT *cert_context)
+{
+ return (cert_context != NULL) &&
+ ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+ (cert_context->pbCertEncoded != NULL) &&
+ (cert_context->cbCertEncoded > 0);
+}
+
+typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
+
+static void
+traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
+ void *arg)
+{
+ const CERT_CONTEXT *current_context = NULL;
+ bool should_continue = true;
+ while(should_continue &&
+ (current_context = CertEnumCertificatesInStore(
+ context->hCertStore,
+ current_context)) != NULL)
+ should_continue = func(current_context, arg);
+
+ if(current_context)
+ CertFreeCertificateContext(current_context);
+}
+
+static bool
+cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
+{
+ if(valid_cert_encoding(ccert_context))
+ (*(int *)certs_count)++;
+ return true;
+}
+
+struct Adder_args
+{
+ struct connectdata *conn;
+ CURLcode result;
+ int idx;
+};
+
+static bool
+add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
+{
+ struct Adder_args *args = (struct Adder_args*)raw_arg;
+ args->result = CURLE_OK;
+ if(valid_cert_encoding(ccert_context)) {
+ const char *beg = (const char *) ccert_context->pbCertEncoded;
+ const char *end = beg + ccert_context->cbCertEncoded;
+ args->result = Curl_extract_certinfo(args->conn, (args->idx)++, beg, end);
+ }
+ return args->result == CURLE_OK;
+}
+
static CURLcode
schannel_connect_step3(struct connectdata *conn, int sockindex)
{
@@ -1129,7 +1204,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
+#ifdef DEBUGBUILD
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
#endif
@@ -1139,8 +1214,9 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
- hostname, conn->remote_port);
+ DEBUGF(infof(data,
+ "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
+ hostname, conn->remote_port));
if(!BACKEND->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1192,6 +1268,8 @@ 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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -1205,7 +1283,8 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
sockindex));
if(incache) {
if(old_cred != BACKEND->cred) {
- infof(data, "schannel: old credential handle is stale, removing\n");
+ 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);
incache = FALSE;
@@ -1223,13 +1302,15 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
else {
/* this cred session is now also referenced by sessionid cache */
BACKEND->cred->refcount++;
- infof(data, "schannel: stored credential handle in session cache\n");
+ DEBUGF(infof(data,
+ "schannel: stored credential handle in session cache\n"));
}
}
Curl_ssl_sessionid_unlock(conn);
}
if(data->set.ssl.certinfo) {
+ int certs_count = 0;
sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
@@ -1238,15 +1319,15 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
return CURLE_PEER_FAILED_VERIFICATION;
}
- result = Curl_ssl_init_certinfo(data, 1);
- if(!result) {
- if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
- (ccert_context->cbCertEncoded > 0)) {
+ traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
- const char *beg = (const char *) ccert_context->pbCertEncoded;
- const char *end = beg + ccert_context->cbCertEncoded;
- result = Curl_extract_certinfo(conn, 0, beg, end);
- }
+ result = Curl_ssl_init_certinfo(data, certs_count);
+ if(!result) {
+ struct Adder_args args;
+ args.conn = conn;
+ args.idx = 0;
+ traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
+ result = args.result;
}
CertFreeCertificateContext(ccert_context);
if(result)
@@ -1359,6 +1440,16 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = schannel_recv;
conn->send[sockindex] = schannel_send;
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* When SSPI is used in combination with Schannel
+ * we need the Schannel context to create the Schannel
+ * binding to pass the IIS extended protection checks.
+ * Available on Windows 7 or later.
+ */
+ conn->sslContext = &BACKEND->ctxt->ctxt_handle;
+#endif
+
*done = TRUE;
}
else
@@ -1543,7 +1634,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
* handled in the cleanup.
*/
- infof(data, "schannel: client wants to read %zu bytes\n", len);
+ DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
*err = CURLE_OK;
if(len && len <= BACKEND->decdata_offset) {
@@ -1588,12 +1679,13 @@ schannel_recv(struct connectdata *conn, int sockindex,
BACKEND->encdata_buffer = reallocated_buffer;
BACKEND->encdata_length = reallocated_length;
size = BACKEND->encdata_length - BACKEND->encdata_offset;
- infof(data, "schannel: encdata_buffer resized %zu\n",
- BACKEND->encdata_length);
+ DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
+ BACKEND->encdata_length));
}
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- BACKEND->encdata_offset, BACKEND->encdata_length);
+ DEBUGF(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu\n",
+ BACKEND->encdata_offset, BACKEND->encdata_length));
/* read encrypted data from socket */
*err = Curl_read_plain(conn->sock[sockindex],
@@ -1603,7 +1695,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
if(*err) {
nread = -1;
if(*err == CURLE_AGAIN)
- infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
+ DEBUGF(infof(data,
+ "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
else if(*err == CURLE_RECV_ERROR)
infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
else
@@ -1611,17 +1704,18 @@ schannel_recv(struct connectdata *conn, int sockindex,
}
else if(nread == 0) {
BACKEND->recv_connection_closed = true;
- infof(data, "schannel: server closed the connection\n");
+ DEBUGF(infof(data, "schannel: server closed the connection\n"));
}
else if(nread > 0) {
BACKEND->encdata_offset += (size_t)nread;
BACKEND->encdata_is_incomplete = false;
- infof(data, "schannel: encrypted data got %zd\n", nread);
+ DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
}
}
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- BACKEND->encdata_offset, BACKEND->encdata_length);
+ DEBUGF(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu\n",
+ BACKEND->encdata_offset, BACKEND->encdata_length));
/* decrypt loop */
while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
@@ -1649,8 +1743,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
/* check for successfully decrypted data, even before actual
renegotiation or shutdown of the connection context */
if(inbuf[1].BufferType == SECBUFFER_DATA) {
- infof(data, "schannel: decrypted data length: %lu\n",
- inbuf[1].cbBuffer);
+ DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
+ inbuf[1].cbBuffer));
/* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
@@ -1682,15 +1776,16 @@ schannel_recv(struct connectdata *conn, int sockindex,
BACKEND->decdata_offset += size;
}
- infof(data, "schannel: decrypted data added: %zu\n", size);
- infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
- BACKEND->decdata_offset, BACKEND->decdata_length);
+ DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
+ DEBUGF(infof(data,
+ "schannel: decrypted cached: offset %zu length %zu\n",
+ BACKEND->decdata_offset, BACKEND->decdata_length));
}
/* check for remaining encrypted data */
if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
- infof(data, "schannel: encrypted data length: %lu\n",
- inbuf[3].cbBuffer);
+ DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+ inbuf[3].cbBuffer));
/* check if the remaining data is less than the total amount
* and therefore begins after the already processed data
@@ -1704,8 +1799,9 @@ schannel_recv(struct connectdata *conn, int sockindex,
BACKEND->encdata_offset = inbuf[3].cbBuffer;
}
- infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
- BACKEND->encdata_offset, BACKEND->encdata_length);
+ DEBUGF(infof(data,
+ "schannel: encrypted cached: offset %zu length %zu\n",
+ BACKEND->encdata_offset, BACKEND->encdata_length));
}
else {
/* reset encrypted buffer offset, because there is no data remaining */
@@ -1759,22 +1855,25 @@ schannel_recv(struct connectdata *conn, int sockindex,
goto cleanup;
}
else {
+ char buffer[STRERROR_LEN];
*err = CURLE_RECV_ERROR;
infof(data, "schannel: failed to read data from server: %s\n",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
goto cleanup;
}
}
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- BACKEND->encdata_offset, BACKEND->encdata_length);
+ DEBUGF(infof(data,
+ "schannel: encrypted data buffer: offset %zu length %zu\n",
+ BACKEND->encdata_offset, BACKEND->encdata_length));
- infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- BACKEND->decdata_offset, BACKEND->decdata_length);
+ DEBUGF(infof(data,
+ "schannel: decrypted data buffer: offset %zu length %zu\n",
+ BACKEND->decdata_offset, BACKEND->decdata_length));
cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
- infof(data, "schannel: schannel_recv cleanup\n");
+ DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
/* Error if the connection has closed without a close_notify.
Behavior here is a matter of debate. We don't want to be vulnerable to a
@@ -1807,10 +1906,10 @@ cleanup:
memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
BACKEND->decdata_offset - size);
BACKEND->decdata_offset -= size;
-
- infof(data, "schannel: decrypted data returned %zu\n", size);
- infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- BACKEND->decdata_offset, BACKEND->decdata_length);
+ DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
+ DEBUGF(infof(data,
+ "schannel: decrypted data buffer: offset %zu length %zu\n",
+ BACKEND->decdata_offset, BACKEND->decdata_length));
*err = CURLE_OK;
return (ssize_t)size;
}
@@ -1888,6 +1987,8 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+ DEBUGASSERT(data);
+
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
hostname, conn->remote_port);
@@ -1907,9 +2008,11 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
&BuffDesc);
- if(sspi_status != SEC_E_OK)
+ if(sspi_status != SEC_E_OK) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: ApplyControlToken failure: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ }
host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
@@ -1951,13 +2054,18 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
/* free SSPI Schannel API security context handle */
if(BACKEND->ctxt) {
- infof(data, "schannel: clear security context handle\n");
+ DEBUGF(infof(data, "schannel: clear security context handle\n"));
s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
Curl_safefree(BACKEND->ctxt);
}
/* 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);
@@ -1994,7 +2102,7 @@ static void Curl_schannel_cleanup(void)
static size_t Curl_schannel_version(char *buffer, size_t size)
{
- size = snprintf(buffer, size, "WinSSL");
+ size = msnprintf(buffer, size, "Schannel");
return size;
}
@@ -2022,14 +2130,9 @@ static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
const char *pinnedpubkey)
{
- SECURITY_STATUS status;
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CERT_CONTEXT *pCertContextServer = NULL;
- const char *x509_der;
- DWORD x509_der_len;
- curl_X509certificate x509_parsed;
- curl_asn1Element *pubkey;
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
@@ -2039,13 +2142,21 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
return CURLE_OK;
do {
- status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
+ SECURITY_STATUS sspi_status;
+ const char *x509_der;
+ DWORD x509_der_len;
+ curl_X509certificate x509_parsed;
+ curl_asn1Element *pubkey;
- if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ sspi_status =
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
+
+ if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
- Curl_sspi_strerror(conn, status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
break; /* failed */
}
@@ -2082,11 +2193,11 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
}
static void Curl_schannel_checksum(const unsigned char *input,
- size_t inputlen,
- unsigned char *checksum,
- size_t checksumlen,
- DWORD provType,
- const unsigned int algId)
+ size_t inputlen,
+ unsigned char *checksum,
+ size_t checksumlen,
+ DWORD provType,
+ const unsigned int algId)
{
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
@@ -2136,9 +2247,9 @@ static CURLcode Curl_schannel_md5sum(unsigned char *input,
unsigned char *md5sum,
size_t md5len)
{
- Curl_schannel_checksum(input, inputlen, md5sum, md5len,
- PROV_RSA_FULL, CALG_MD5);
- return CURLE_OK;
+ Curl_schannel_checksum(input, inputlen, md5sum, md5len,
+ PROV_RSA_FULL, CALG_MD5);
+ return CURLE_OK;
}
static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
@@ -2146,9 +2257,9 @@ static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
unsigned char *sha256sum,
size_t sha256len)
{
- Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
- PROV_RSA_AES, CALG_SHA_256);
- return CURLE_OK;
+ Curl_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,
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
index e491bd431..ee8d7d47a 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.h
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -8,7 +8,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2018, 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
@@ -53,7 +53,7 @@
extern const struct Curl_ssl Curl_ssl_schannel;
-CURLcode verify_certificate(struct connectdata *conn, int sockindex);
+CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex);
/* structs to expose only in schannel.c and schannel_verify.c */
#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 2516f5665..5a09e969e 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -23,7 +23,7 @@
***************************************************************************/
/*
- * Source file for SChannel-specific certificate verification. This code should
+ * Source file for Schannel-specific certificate verification. This code should
* only be invoked by code in schannel.c.
*/
@@ -87,18 +87,19 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
LARGE_INTEGER file_size;
char *ca_file_buffer = NULL;
char *current_ca_file_ptr = NULL;
- const TCHAR *ca_file_tstr = NULL;
+ TCHAR *ca_file_tstr = NULL;
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
bool more_certs = 0;
int num_certs = 0;
size_t END_CERT_LEN;
- ca_file_tstr = Curl_convert_UTF8_to_tchar(ca_file);
+ ca_file_tstr = Curl_convert_UTF8_to_tchar((char *)ca_file);
if(!ca_file_tstr) {
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: invalid path name for CA file '%s': %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file, Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -116,17 +117,19 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(ca_file_handle == INVALID_HANDLE_VALUE) {
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to open CA file '%s': %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file, Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
if(!GetFileSizeEx(ca_file_handle, &file_size)) {
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to determine size of CA file '%s': %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file, Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -153,10 +156,10 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
bytes_to_read, &bytes_read, NULL)) {
-
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to read from CA file '%s': %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file, Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -215,11 +218,12 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
NULL,
NULL,
(const void **)&cert_context)) {
-
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to extract certificate from CA file "
"'%s': %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file,
+ Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -243,10 +247,12 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
NULL);
CertFreeCertificateContext(cert_context);
if(!add_cert_result) {
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to add certificate from CA file '%s' "
"to certificate store: %s",
- ca_file, Curl_strerror(conn, GetLastError()));
+ ca_file,
+ Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -406,9 +412,9 @@ cleanup:
return result;
}
-CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
{
- SECURITY_STATUS status;
+ SECURITY_STATUS sspi_status;
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result = CURLE_OK;
@@ -420,13 +426,15 @@ CURLcode verify_certificate(struct connectdata *conn, int sockindex)
conn->http_proxy.host.name :
conn->host.name;
- status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
+ sspi_status =
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
- if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
- Curl_sspi_strerror(conn, status));
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
result = CURLE_PEER_FAILED_VERIFICATION;
}
@@ -450,8 +458,9 @@ CURLcode verify_certificate(struct connectdata *conn, int sockindex)
CERT_STORE_CREATE_NEW_FLAG,
NULL);
if(!trust_store) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: failed to create certificate store: %s",
- Curl_strerror(conn, GetLastError()));
+ Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -477,9 +486,10 @@ CURLcode verify_certificate(struct connectdata *conn, int sockindex)
CertCreateCertificateChainEngine(
(CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
if(!create_engine_result) {
+ char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to create certificate chain engine: %s",
- Curl_strerror(conn, GetLastError()));
+ Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
}
@@ -500,8 +510,9 @@ CURLcode verify_certificate(struct connectdata *conn, int sockindex)
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
+ char buffer[STRERROR_LEN];
failf(data, "schannel: CertGetCertificateChain failed: %s",
- Curl_sspi_strerror(conn, GetLastError()));
+ Curl_strerror(GetLastError(), buffer, sizeof(buffer)));
pChainContext = NULL;
result = CURLE_PEER_FAILED_VERIFICATION;
}
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index e8116b8a1..2fdf662a1 100644
--- a/Utilities/cmcurl/lib/vtls/darwinssl.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -31,8 +31,9 @@
#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
#include "strtok.h"
+#include "multiif.h"
-#ifdef USE_DARWINSSL
+#ifdef USE_SECTRANSP
#ifdef __clang__
#pragma clang diagnostic push
@@ -59,7 +60,7 @@
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
-#error "The darwinssl back-end requires Leopard or later."
+#error "The Secure Transport back-end requires Leopard or later."
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
#define CURL_BUILD_IOS 0
@@ -105,7 +106,7 @@
#define CURL_SUPPORT_MAC_10_9 0
#else
-#error "The darwinssl back-end requires iOS or OS X."
+#error "The Secure Transport back-end requires iOS or macOS."
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
#if CURL_BUILD_MAC
@@ -118,7 +119,7 @@
#include "connect.h"
#include "select.h"
#include "vtls.h"
-#include "darwinssl.h"
+#include "sectransp.h"
#include "curl_printf.h"
#include "strdup.h"
@@ -144,20 +145,20 @@ struct ssl_backend_data {
/* version 1 supports macOS 10.12+ and iOS 10+ */
#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
(!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200))
-#define DARWIN_SSL_PINNEDPUBKEY_V1 1
+#define SECTRANSP_PINNEDPUBKEY_V1 1
#endif
/* version 2 supports MacOSX 10.7+ */
#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
-#define DARWIN_SSL_PINNEDPUBKEY_V2 1
+#define SECTRANSP_PINNEDPUBKEY_V2 1
#endif
-#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2)
+#if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2)
/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define DARWIN_SSL_PINNEDPUBKEY 1
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
+#define SECTRANSP_PINNEDPUBKEY 1
+#endif /* SECTRANSP_PINNEDPUBKEY */
-#ifdef DARWIN_SSL_PINNEDPUBKEY
+#ifdef SECTRANSP_PINNEDPUBKEY
/* both new and old APIs return rsa keys missing the spki header (not DER) */
static const unsigned char rsa4096SpkiHeader[] = {
0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
@@ -170,7 +171,7 @@ static const unsigned char rsa2048SpkiHeader[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
-#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
@@ -184,8 +185,8 @@ static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
0x00, 0x22, 0x03, 0x62, 0x00};
-#endif /* DARWIN_SSL_PINNEDPUBKEY_V1 */
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
+#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
+#endif /* SECTRANSP_PINNEDPUBKEY */
/* The following two functions were ripped from Apple sample code,
* with some modifications: */
@@ -950,7 +951,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
if(!c) {
failf(data, "SSL: invalid CA certificate subject");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
}
/* If the subject is already available as UTF-8 encoded (ie 'direct') then
@@ -970,7 +971,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
if(!CFStringGetCString(c, cbuf, cbuf_size,
kCFStringEncodingUTF8)) {
failf(data, "SSL: invalid CA certificate subject");
- result = CURLE_SSL_CACERT;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else
/* pass back the buffer */
@@ -1242,7 +1243,7 @@ CF_INLINE bool is_file(const char *filename)
}
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-static CURLcode darwinssl_version_from_curl(SSLProtocol *darwinver,
+static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
long ssl_version)
{
switch(ssl_version) {
@@ -1298,7 +1299,6 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
- ssl_version_max = max_supported_version_by_os;
break;
}
@@ -1313,13 +1313,13 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
if(SSLSetProtocolVersionMax != NULL) {
SSLProtocol darwin_ver_min = kTLSProtocol1;
SSLProtocol darwin_ver_max = kTLSProtocol1;
- CURLcode result = darwinssl_version_from_curl(&darwin_ver_min,
+ CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
ssl_version);
if(result) {
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
- result = darwinssl_version_from_curl(&darwin_ver_max,
+ result = sectransp_version_from_curl(&darwin_ver_max,
ssl_version_max >> 16);
if(result) {
failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
@@ -1362,12 +1362,12 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- failf(data, "DarwinSSL: cannot set SSL protocol");
+ failf(data, "Secure Transport: cannot set SSL protocol");
return CURLE_SSL_CONNECT_ERROR;
}
-static CURLcode darwinssl_connect_step1(struct connectdata *conn,
+static CURLcode sectransp_connect_step1(struct connectdata *conn,
int sockindex)
{
struct Curl_easy *data = conn->data;
@@ -1430,7 +1430,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax != NULL) {
switch(conn->ssl_config.version) {
- case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
@@ -1445,6 +1444,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
HAVE_BUILTIN_AVAILABLE == 1 */
break;
+ case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
@@ -1578,7 +1578,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
if(conn->bits.tls_enable_alpn) {
- if(__builtin_available(macOS 10.13.4, iOS 11, *)) {
+ if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
@@ -1649,7 +1649,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
CFRelease(cert);
- if(result == CURLE_SSL_CACERT)
+ if(result == CURLE_PEER_FAILED_VERIFICATION)
return CURLE_SSL_CERTPROBLEM;
if(result)
return result;
@@ -1903,7 +1903,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* We want to enable 1/n-1 when using a CBC cipher unless the user
specifically doesn't want us doing that: */
if(SSLSetSessionOption != NULL) {
- /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */
SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
!data->set.ssl.enable_beast);
SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart,
@@ -2235,7 +2234,7 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
}
}
-#ifdef DARWIN_SSL_PINNEDPUBKEY
+#ifdef SECTRANSP_PINNEDPUBKEY
static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
SSLContextRef ctx,
const char *pinnedpubkey)
@@ -2267,14 +2266,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
if(keyRef == NULL)
break;
-#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
CFRelease(keyRef);
if(publicKeyBits == NULL)
break;
-#elif DARWIN_SSL_PINNEDPUBKEY_V2
+#elif SECTRANSP_PINNEDPUBKEY_V2
OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
&publicKeyBits);
@@ -2282,7 +2281,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
if(success != errSecSuccess || publicKeyBits == NULL)
break;
-#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */
+#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
pubkeylen = CFDataGetLength(publicKeyBits);
pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
@@ -2296,7 +2295,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
/* 2048 bit RSA pubkeylen == 270 */
spkiHeader = rsa2048SpkiHeader;
break;
-#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
case 65:
/* ecDSA secp256r1 pubkeylen == 65 */
spkiHeader = ecDsaSecp256r1SpkiHeader;
@@ -2309,7 +2308,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
break;
default:
infof(data, "SSL: unhandled public key length: %d\n", pubkeylen);
-#elif DARWIN_SSL_PINNEDPUBKEY_V2
+#elif SECTRANSP_PINNEDPUBKEY_V2
default:
/* ecDSA secp256r1 pubkeylen == 91 header already included?
* ecDSA secp384r1 header already included too
@@ -2317,7 +2316,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
*/
result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey,
pubkeylen);
-#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */
+#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
continue; /* break from loop */
}
@@ -2340,10 +2339,10 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
return result;
}
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
+#endif /* SECTRANSP_PINNEDPUBKEY */
static CURLcode
-darwinssl_connect_step2(struct connectdata *conn, int sockindex)
+sectransp_connect_step2(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -2377,7 +2376,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
return res;
}
/* the documentation says we need to call SSLHandshake() again */
- return darwinssl_connect_step2(conn, sockindex);
+ return sectransp_connect_step2(conn, sockindex);
/* Problem with encrypt / decrypt */
case errSSLPeerDecodeError:
@@ -2429,37 +2428,37 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* These are all certificate problems with the server: */
case errSSLXCertChainInvalid:
failf(data, "SSL certificate problem: Invalid certificate chain");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLUnknownRootCert:
failf(data, "SSL certificate problem: Untrusted root certificate");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLNoRootCert:
failf(data, "SSL certificate problem: No root certificate");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLCertNotYetValid:
failf(data, "SSL certificate problem: The certificate chain had a "
"certificate that is not yet valid");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLCertExpired:
case errSSLPeerCertExpired:
failf(data, "SSL certificate problem: Certificate chain had an "
"expired certificate");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLBadCert:
case errSSLPeerBadCert:
failf(data, "SSL certificate problem: Couldn't understand the server "
"certificate format");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLPeerUnsupportedCert:
failf(data, "SSL certificate problem: An unsupported certificate "
"format was encountered");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLPeerCertRevoked:
failf(data, "SSL certificate problem: The certificate was revoked");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
case errSSLPeerCertUnknown:
failf(data, "SSL certificate problem: The certificate is unknown");
- return CURLE_SSL_CACERT;
+ return CURLE_PEER_FAILED_VERIFICATION;
/* These are all certificate problems with the client: */
case errSecAuthFailed:
@@ -2579,7 +2578,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* we have been connected fine, we're not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
-#ifdef DARWIN_SSL_PINNEDPUBKEY
+#ifdef SECTRANSP_PINNEDPUBKEY
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) {
CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx,
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]);
@@ -2588,7 +2587,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
return result;
}
}
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
+#endif /* SECTRANSP_PINNEDPUBKEY */
/* Informational message */
(void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher);
@@ -2629,7 +2628,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
if(conn->bits.tls_enable_alpn) {
- if(__builtin_available(macOS 10.13.4, iOS 11, *)) {
+ if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFArrayRef alpnArr = NULL;
CFStringRef chosenProtocol = NULL;
err = SSLCopyALPNProtocols(BACKEND->ssl_ctx, &alpnArr);
@@ -2652,6 +2651,9 @@ darwinssl_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 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+
/* chosenProtocol is a reference to the string within alpnArr
and doesn't need to be freed separately */
if(alpnArr)
@@ -2772,7 +2774,7 @@ show_verbose_server_cert(struct connectdata *conn,
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
static CURLcode
-darwinssl_connect_step3(struct connectdata *conn,
+sectransp_connect_step3(struct connectdata *conn,
int sockindex)
{
struct Curl_easy *data = conn->data;
@@ -2790,11 +2792,11 @@ darwinssl_connect_step3(struct connectdata *conn,
return CURLE_OK;
}
-static Curl_recv darwinssl_recv;
-static Curl_send darwinssl_send;
+static Curl_recv sectransp_recv;
+static Curl_send sectransp_send;
static CURLcode
-darwinssl_connect_common(struct connectdata *conn,
+sectransp_connect_common(struct connectdata *conn,
int sockindex,
bool nonblocking,
bool *done)
@@ -2822,7 +2824,7 @@ darwinssl_connect_common(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
- result = darwinssl_connect_step1(conn, sockindex);
+ result = sectransp_connect_step1(conn, sockindex);
if(result)
return result;
}
@@ -2876,7 +2878,7 @@ darwinssl_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 = darwinssl_connect_step2(conn, sockindex);
+ result = sectransp_connect_step2(conn, sockindex);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -2887,15 +2889,15 @@ darwinssl_connect_common(struct connectdata *conn,
if(ssl_connect_3 == connssl->connecting_state) {
- result = darwinssl_connect_step3(conn, sockindex);
+ result = sectransp_connect_step3(conn, sockindex);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = darwinssl_recv;
- conn->send[sockindex] = darwinssl_send;
+ conn->recv[sockindex] = sectransp_recv;
+ conn->send[sockindex] = sectransp_send;
*done = TRUE;
}
else
@@ -2907,18 +2909,18 @@ darwinssl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-static CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+static CURLcode Curl_sectransp_connect_nonblocking(struct connectdata *conn,
int sockindex, bool *done)
{
- return darwinssl_connect_common(conn, sockindex, TRUE, done);
+ return sectransp_connect_common(conn, sockindex, TRUE, done);
}
-static CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
- result = darwinssl_connect_common(conn, sockindex, FALSE, &done);
+ result = sectransp_connect_common(conn, sockindex, FALSE, &done);
if(result)
return result;
@@ -2928,7 +2930,7 @@ static CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-static void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
+static void Curl_sectransp_close(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -2949,7 +2951,7 @@ static void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
BACKEND->ssl_sockfd = 0;
}
-static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
@@ -2961,10 +2963,12 @@ static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
if(!BACKEND->ssl_ctx)
return 0;
+#ifndef CURL_DISABLE_FTP
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
return 0;
+#endif
- Curl_darwinssl_close(conn, sockindex);
+ Curl_sectransp_close(conn, sockindex);
rc = 0;
@@ -3002,20 +3006,20 @@ static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
return rc;
}
-static void Curl_darwinssl_session_free(void *ptr)
+static void Curl_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
function that does this, but I don't want to have to explain to you why I
got your application rejected from the App Store due to the use of a
private API, so the best we can do is free up our own char array that we
- created way back in darwinssl_connect_step1... */
+ created way back in sectransp_connect_step1... */
Curl_safefree(ptr);
}
-static size_t Curl_darwinssl_version(char *buffer, size_t size)
+static size_t Curl_sectransp_version(char *buffer, size_t size)
{
- return snprintf(buffer, size, "SecureTransport");
+ return msnprintf(buffer, size, "SecureTransport");
}
/*
@@ -3026,7 +3030,7 @@ static size_t Curl_darwinssl_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int Curl_darwinssl_check_cxn(struct connectdata *conn)
+static int Curl_sectransp_check_cxn(struct connectdata *conn)
{
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
OSStatus err;
@@ -3041,7 +3045,7 @@ static int Curl_darwinssl_check_cxn(struct connectdata *conn)
return 0;
}
-static bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+static bool Curl_sectransp_data_pending(const struct connectdata *conn,
int connindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[connindex];
@@ -3058,7 +3062,7 @@ static bool Curl_darwinssl_data_pending(const struct connectdata *conn,
return false;
}
-static CURLcode Curl_darwinssl_random(struct Curl_easy *data UNUSED_PARAM,
+static CURLcode Curl_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
@@ -3078,7 +3082,7 @@ static CURLcode Curl_darwinssl_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+static CURLcode Curl_sectransp_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum, /* output */
size_t md5len)
@@ -3088,7 +3092,7 @@ static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
return CURLE_OK;
}
-static CURLcode Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
+static CURLcode Curl_sectransp_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len)
@@ -3098,7 +3102,7 @@ static CURLcode Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
return CURLE_OK;
}
-static bool Curl_darwinssl_false_start(void)
+static bool Curl_sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
if(SSLSetSessionOption != NULL)
@@ -3107,7 +3111,7 @@ static bool Curl_darwinssl_false_start(void)
return FALSE;
}
-static ssize_t darwinssl_send(struct connectdata *conn,
+static ssize_t sectransp_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len,
@@ -3173,7 +3177,7 @@ static ssize_t darwinssl_send(struct connectdata *conn,
return (ssize_t)processed;
}
-static ssize_t darwinssl_recv(struct connectdata *conn,
+static ssize_t sectransp_recv(struct connectdata *conn,
int num,
char *buf,
size_t buffersize,
@@ -3213,48 +3217,48 @@ static ssize_t darwinssl_recv(struct connectdata *conn,
return (ssize_t)processed;
}
-static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl,
+static void *Curl_sectransp_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
(void)info;
return BACKEND->ssl_ctx;
}
-const struct Curl_ssl Curl_ssl_darwinssl = {
- { CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */
+const struct Curl_ssl Curl_ssl_sectransp = {
+ { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
-#ifdef DARWIN_SSL_PINNEDPUBKEY
+#ifdef SECTRANSP_PINNEDPUBKEY
SSLSUPP_PINNEDPUBKEY,
#else
0,
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
+#endif /* SECTRANSP_PINNEDPUBKEY */
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */
Curl_none_cleanup, /* cleanup */
- Curl_darwinssl_version, /* version */
- Curl_darwinssl_check_cxn, /* check_cxn */
- Curl_darwinssl_shutdown, /* shutdown */
- Curl_darwinssl_data_pending, /* data_pending */
- Curl_darwinssl_random, /* random */
+ Curl_sectransp_version, /* version */
+ Curl_sectransp_check_cxn, /* check_cxn */
+ Curl_sectransp_shutdown, /* shutdown */
+ Curl_sectransp_data_pending, /* data_pending */
+ Curl_sectransp_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
- Curl_darwinssl_connect, /* connect */
- Curl_darwinssl_connect_nonblocking, /* connect_nonblocking */
- Curl_darwinssl_get_internals, /* get_internals */
- Curl_darwinssl_close, /* close_one */
+ Curl_sectransp_connect, /* connect */
+ Curl_sectransp_connect_nonblocking, /* connect_nonblocking */
+ Curl_sectransp_get_internals, /* get_internals */
+ Curl_sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
- Curl_darwinssl_session_free, /* session_free */
+ Curl_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_darwinssl_false_start, /* false_start */
- Curl_darwinssl_md5sum, /* md5sum */
- Curl_darwinssl_sha256sum /* sha256sum */
+ Curl_sectransp_false_start, /* false_start */
+ Curl_sectransp_md5sum, /* md5sum */
+ Curl_sectransp_sha256sum /* sha256sum */
};
#ifdef __clang__
#pragma clang diagnostic pop
#endif
-#endif /* USE_DARWINSSL */
+#endif /* USE_SECTRANSP */
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.h b/Utilities/cmcurl/lib/vtls/sectransp.h
index 23c7f705c..5cec797b3 100644
--- a/Utilities/cmcurl/lib/vtls/darwinssl.h
+++ b/Utilities/cmcurl/lib/vtls/sectransp.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_DARWINSSL_H
-#define HEADER_CURL_DARWINSSL_H
+#ifndef HEADER_CURL_SECTRANSP_H
+#define HEADER_CURL_SECTRANSP_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -8,7 +8,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -24,9 +24,9 @@
***************************************************************************/
#include "curl_setup.h"
-#ifdef USE_DARWINSSL
+#ifdef USE_SECTRANSP
-extern const struct Curl_ssl Curl_ssl_darwinssl;
+extern const struct Curl_ssl Curl_ssl_sectransp;
-#endif /* USE_DARWINSSL */
-#endif /* HEADER_CURL_DARWINSSL_H */
+#endif /* USE_SECTRANSP */
+#endif /* HEADER_CURL_SECTRANSP_H */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 6af39feab..a7452dcd5 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -248,7 +248,7 @@ Curl_ssl_connect(struct connectdata *conn, int sockindex)
conn->ssl[sockindex].use = TRUE;
conn->ssl[sockindex].state = ssl_connection_negotiating;
- result = Curl_ssl->connect(conn, sockindex);
+ result = Curl_ssl->connect_blocking(conn, sockindex);
if(!result)
Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
@@ -498,9 +498,9 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
void Curl_ssl_close_all(struct Curl_easy *data)
{
- size_t i;
/* kill the session ID cache if not shared */
if(data->state.session && !SSLSESSION_SHARED(data)) {
+ size_t i;
for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
/* the single-killer function handles empty table slots */
Curl_ssl_kill_session(&data->state.session[i]);
@@ -513,7 +513,7 @@ void Curl_ssl_close_all(struct Curl_easy *data)
}
#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
- defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \
+ defined(USE_SECTRANSP) || defined(USE_POLARSSL) || defined(USE_NSS) || \
defined(USE_MBEDTLS) || defined(USE_CYASSL)
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks)
@@ -546,7 +546,7 @@ int Curl_ssl_getsock(struct connectdata *conn,
(void)numsocks;
return GETSOCK_BLANK;
}
-/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */
+/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */
#endif
void Curl_ssl_close(struct connectdata *conn, int sockindex)
@@ -557,7 +557,7 @@ void Curl_ssl_close(struct connectdata *conn, int sockindex)
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
{
- if(Curl_ssl->shutdown(conn, sockindex))
+ if(Curl_ssl->shut_down(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
@@ -644,11 +644,11 @@ bool Curl_ssl_data_pending(const struct connectdata *conn,
void Curl_ssl_free_certinfo(struct Curl_easy *data)
{
- int i;
struct curl_certinfo *ci = &data->info.certs;
if(ci->num_of_certs) {
/* free all individual lists used */
+ int i;
for(i = 0; i<ci->num_of_certs; i++) {
curl_slist_free_all(ci->certinfo[i]);
ci->certinfo[i] = NULL;
@@ -700,7 +700,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* sprintf the label and colon */
- snprintf(output, outlen, "%s:", label);
+ msnprintf(output, outlen, "%s:", label);
/* memcpy the value (it might not be zero terminated) */
memcpy(&output[labellen + 1], value, valuelen);
@@ -808,14 +808,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
{
FILE *fp;
unsigned char *buf = NULL, *pem_ptr = NULL;
- long filesize;
- size_t size, pem_len;
- CURLcode pem_read;
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- CURLcode encode;
- size_t encodedlen, pinkeylen;
- char *encoded, *pinkeycopy, *begin_pos, *end_pos;
- unsigned char *sha256sumdigest = NULL;
/* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
@@ -825,6 +818,11 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+ CURLcode encode;
+ size_t encodedlen, pinkeylen;
+ char *encoded, *pinkeycopy, *begin_pos, *end_pos;
+ unsigned char *sha256sumdigest;
+
if(!Curl_ssl->sha256sum) {
/* without sha256 support, this cannot match */
return result;
@@ -895,6 +893,10 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
return result;
do {
+ long filesize;
+ size_t size, pem_len;
+ CURLcode pem_read;
+
/* Determine the file's size */
if(fseek(fp, 0, SEEK_END))
break;
@@ -1114,7 +1116,7 @@ static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex)
{
if(multissl_init(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect(conn, sockindex);
+ return Curl_ssl->connect_blocking(conn, sockindex);
}
static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn,
@@ -1170,12 +1172,10 @@ static const struct Curl_ssl Curl_ssl_multi = {
const struct Curl_ssl *Curl_ssl =
#if defined(CURL_WITH_MULTI_SSL)
&Curl_ssl_multi;
-#elif defined(USE_AXTLS)
- &Curl_ssl_axtls;
#elif defined(USE_CYASSL)
&Curl_ssl_cyassl;
-#elif defined(USE_DARWINSSL)
- &Curl_ssl_darwinssl;
+#elif defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
&Curl_ssl_gnutls;
#elif defined(USE_GSKIT)
@@ -1197,14 +1197,11 @@ const struct Curl_ssl *Curl_ssl =
#endif
static const struct Curl_ssl *available_backends[] = {
-#if defined(USE_AXTLS)
- &Curl_ssl_axtls,
-#endif
#if defined(USE_CYASSL)
&Curl_ssl_cyassl,
#endif
-#if defined(USE_DARWINSSL)
- &Curl_ssl_darwinssl,
+#if defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp,
#endif
#if defined(USE_GNUTLS)
&Curl_ssl_gnutls,
@@ -1244,16 +1241,17 @@ static size_t Curl_multissl_version(char *buffer, size_t size)
if(current != selected) {
char *p = backends;
+ char *end = backends + sizeof(backends);
int i;
selected = current;
- for(i = 0; available_backends[i]; i++) {
+ for(i = 0; available_backends[i] && p < (end - 4); i++) {
if(i)
*(p++) = ' ';
if(selected != available_backends[i])
*(p++) = '(';
- p += available_backends[i]->version(p, backends + sizeof(backends) - p);
+ p += available_backends[i]->version(p, end - p - 2);
if(selected != available_backends[i])
*(p++) = ')';
}
@@ -1261,21 +1259,20 @@ static size_t Curl_multissl_version(char *buffer, size_t size)
total = p - backends;
}
- if(size < total)
+ if(size > total)
memcpy(buffer, backends, total + 1);
else {
memcpy(buffer, backends, size - 1);
buffer[size - 1] = '\0';
}
- return total;
+ return CURLMIN(size - 1, total);
}
static int multissl_init(const struct Curl_ssl *backend)
{
const char *env;
char *env_tmp;
- int i;
if(Curl_ssl != &Curl_ssl_multi)
return 1;
@@ -1294,6 +1291,7 @@ static int multissl_init(const struct Curl_ssl *backend)
env = CURL_DEFAULT_SSL_BACKEND;
#endif
if(env) {
+ int i;
for(i = 0; available_backends[i]; i++) {
if(strcasecompare(env, available_backends[i]->info.name)) {
Curl_ssl = available_backends[i];
@@ -1318,7 +1316,14 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
*avail = (const curl_ssl_backend **)&available_backends;
if(Curl_ssl != &Curl_ssl_multi)
- return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE;
+ return id == Curl_ssl->info.id ||
+ (name && strcasecompare(name, Curl_ssl->info.name)) ?
+ CURLSSLSET_OK :
+#if defined(CURL_WITH_MULTI_SSL)
+ CURLSSLSET_TOO_LATE;
+#else
+ CURLSSLSET_UNKNOWN_BACKEND;
+#endif
for(i = 0; available_backends[i]; i++) {
if(available_backends[i]->info.id == id ||
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 5cd11602e..2a87ca1f7 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -47,7 +47,7 @@ struct Curl_ssl {
size_t (*version)(char *buffer, size_t size);
int (*check_cxn)(struct connectdata *cxn);
- int (*shutdown)(struct connectdata *conn, int sockindex);
+ int (*shut_down)(struct connectdata *conn, int sockindex);
bool (*data_pending)(const struct connectdata *conn,
int connindex);
@@ -56,7 +56,7 @@ struct Curl_ssl {
size_t length);
bool (*cert_status_request)(void);
- CURLcode (*connect)(struct connectdata *conn, int sockindex);
+ CURLcode (*connect_blocking)(struct connectdata *conn, int sockindex);
CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex,
bool *done);
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
@@ -103,10 +103,9 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
#include "nssg.h" /* NSS versions */
#include "gskit.h" /* Global Secure ToolKit versions */
#include "polarssl.h" /* PolarSSL versions */
-#include "axtls.h" /* axTLS versions */
#include "cyassl.h" /* CyaSSL versions */
#include "schannel.h" /* Schannel SSPI version */
-#include "darwinssl.h" /* SecureTransport (Darwin) version */
+#include "sectransp.h" /* SecureTransport (Darwin) version */
#include "mbedtls.h" /* mbedTLS versions */
#include "mesalink.h" /* MesaLink versions */
diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c
index 05d9038dc..cfd5e8e14 100644
--- a/Utilities/cmcurl/lib/warnless.c
+++ b/Utilities/cmcurl/lib/warnless.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -401,44 +401,6 @@ unsigned short curlx_uitous(unsigned int uinum)
}
/*
-** unsigned int to unsigned char
-*/
-
-unsigned char curlx_uitouc(unsigned int uinum)
-{
-#ifdef __INTEL_COMPILER
-# pragma warning(push)
-# pragma warning(disable:810) /* conversion may lose significant bits */
-#endif
-
- DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR);
- return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR);
-
-#ifdef __INTEL_COMPILER
-# pragma warning(pop)
-#endif
-}
-
-/*
-** unsigned int to signed int
-*/
-
-int curlx_uitosi(unsigned int uinum)
-{
-#ifdef __INTEL_COMPILER
-# pragma warning(push)
-# pragma warning(disable:810) /* conversion may lose significant bits */
-#endif
-
- DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT);
- return (int) (uinum & (unsigned int) CURL_MASK_SINT);
-
-#ifdef __INTEL_COMPILER
-# pragma warning(pop)
-#endif
-}
-
-/*
** signed int to unsigned size_t
*/
diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h
index 284ea1e75..ea4c4395d 100644
--- a/Utilities/cmcurl/lib/warnless.h
+++ b/Utilities/cmcurl/lib/warnless.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -57,10 +57,6 @@ int curlx_sztosi(ssize_t sznum);
unsigned short curlx_uitous(unsigned int uinum);
-unsigned char curlx_uitouc(unsigned int uinum);
-
-int curlx_uitosi(unsigned int uinum);
-
size_t curlx_sitouz(int sinum);
#ifdef USE_WINSOCK
diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c
index 8ba0989b4..e94d3c544 100644
--- a/Utilities/cmcurl/lib/wildcard.c
+++ b/Utilities/cmcurl/lib/wildcard.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -22,6 +22,8 @@
#include "curl_setup.h"
+#ifndef CURL_DISABLE_FTP
+
#include "wildcard.h"
#include "llist.h"
#include "fileinfo.h"
@@ -67,3 +69,5 @@ void Curl_wildcard_dtor(struct WildcardData *wc)
wc->customptr = NULL;
wc->state = CURLWC_INIT;
}
+
+#endif /* if disabled */
diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h
index b7826123a..306c8c99f 100644
--- a/Utilities/cmcurl/lib/wildcard.h
+++ b/Utilities/cmcurl/lib/wildcard.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2019, 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
@@ -22,8 +22,9 @@
*
***************************************************************************/
-#include <curl/curl.h>
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_FTP
#include "llist.h"
/* list of wildcard process states */
@@ -58,4 +59,9 @@ void Curl_wildcard_dtor(struct WildcardData *wc);
struct Curl_easy;
+#else
+/* FTP is disabled */
+#define Curl_wildcard_dtor(x)
+#endif
+
#endif /* HEADER_CURL_WILDCARD_H */
diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c
index a576fc703..0c1256ba8 100644
--- a/Utilities/cmcurl/lib/x509asn1.c
+++ b/Utilities/cmcurl/lib/x509asn1.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -120,7 +120,7 @@ static const char *getASN1Element(curl_asn1Element *elem,
if an error occurs. */
if(!beg || !end || beg >= end || !*beg ||
(size_t)(end - beg) > CURL_ASN1_MAX)
- return (const char *) NULL;
+ return NULL;
/* Process header byte. */
elem->header = beg;
@@ -129,12 +129,12 @@ static const char *getASN1Element(curl_asn1Element *elem,
elem->class = (b >> 6) & 3;
b &= 0x1F;
if(b == 0x1F)
- return (const char *) NULL; /* Long tag values not supported here. */
+ return NULL; /* Long tag values not supported here. */
elem->tag = b;
/* Process length. */
if(beg >= end)
- return (const char *) NULL;
+ return NULL;
b = (unsigned char) *beg++;
if(!(b & 0x80))
len = b;
@@ -142,74 +142,77 @@ static const char *getASN1Element(curl_asn1Element *elem,
/* Unspecified length. Since we have all the data, we can determine the
effective length by skipping element until an end element is found. */
if(!elem->constructed)
- return (const char *) NULL;
+ return NULL;
elem->beg = beg;
while(beg < end && *beg) {
beg = getASN1Element(&lelem, beg, end);
if(!beg)
- return (const char *) NULL;
+ return NULL;
}
if(beg >= end)
- return (const char *) NULL;
+ return NULL;
elem->end = beg;
return beg + 1;
}
else if((unsigned)b > (size_t)(end - beg))
- return (const char *) NULL; /* Does not fit in source. */
+ return NULL; /* Does not fit in source. */
else {
/* Get long length. */
len = 0;
do {
if(len & 0xFF000000L)
- return (const char *) NULL; /* Lengths > 32 bits are not supported. */
+ return NULL; /* Lengths > 32 bits are not supported. */
len = (len << 8) | (unsigned char) *beg++;
} while(--b);
}
if(len > (size_t)(end - beg))
- return (const char *) NULL; /* Element data does not fit in source. */
+ return NULL; /* Element data does not fit in source. */
elem->beg = beg;
elem->end = beg + len;
return elem->end;
}
+/*
+ * Search the null terminated OID or OID identifier in local table.
+ * Return the table entry pointer or NULL if not found.
+ */
static const curl_OID * searchOID(const char *oid)
{
const curl_OID *op;
-
- /* Search the null terminated OID or OID identifier in local table.
- Return the table entry pointer or NULL if not found. */
-
for(op = OIDtable; op->numoid; op++)
if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
return op;
- return (const curl_OID *) NULL;
+ return NULL;
}
+/*
+ * Convert an ASN.1 Boolean value into its string representation. Return the
+ * dynamically allocated string, or NULL if source is not an ASN.1 Boolean
+ * value.
+ */
+
static const char *bool2str(const char *beg, const char *end)
{
- /* Convert an ASN.1 Boolean value into its string representation.
- Return the dynamically allocated string, or NULL if source is not an
- ASN.1 Boolean value. */
-
if(end - beg != 1)
- return (const char *) NULL;
+ return NULL;
return strdup(*beg? "TRUE": "FALSE");
}
+/*
+ * Convert an ASN.1 octet string to a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
static const char *octet2str(const char *beg, const char *end)
{
size_t n = end - beg;
char *buf = NULL;
- /* Convert an ASN.1 octet string to a printable string.
- Return the dynamically allocated string, or NULL if an error occurs. */
-
if(n <= (SIZE_T_MAX - 1) / 3) {
buf = malloc(3 * n + 1);
if(buf)
for(n = 0; beg < end; n += 3)
- snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
+ msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
}
return buf;
}
@@ -220,21 +223,22 @@ static const char *bit2str(const char *beg, const char *end)
Return the dynamically allocated string, or NULL if an error occurs. */
if(++beg > end)
- return (const char *) NULL;
+ return NULL;
return octet2str(beg, end);
}
+/*
+ * Convert an ASN.1 integer value into its string representation.
+ * Return the dynamically allocated string, or NULL if source is not an
+ * ASN.1 integer value.
+ */
static const char *int2str(const char *beg, const char *end)
{
unsigned long val = 0;
size_t n = end - beg;
- /* Convert an ASN.1 integer value into its string representation.
- Return the dynamically allocated string, or NULL if source is not an
- ASN.1 integer value. */
-
if(!n)
- return (const char *) NULL;
+ return NULL;
if(n > 4)
return octet2str(beg, end);
@@ -249,23 +253,22 @@ static const char *int2str(const char *beg, const char *end)
return curl_maprintf("%s%lx", val >= 10? "0x": "", val);
}
+/*
+ * Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
+ * destination buffer dynamically. The allocation size will normally be too
+ * large: this is to avoid buffer overflows.
+ * Terminate the string with a nul byte and return the converted
+ * string length.
+ */
static ssize_t
utf8asn1str(char **to, int type, const char *from, const char *end)
{
size_t inlength = end - from;
int size = 1;
size_t outlength;
- int charsize;
- unsigned int wc;
char *buf;
- /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
- destination buffer dynamically. The allocation size will normally be too
- large: this is to avoid buffer overflows.
- Terminate the string with a nul byte and return the converted
- string length. */
-
- *to = (char *) NULL;
+ *to = NULL;
switch(type) {
case CURL_ASN1_BMP_STRING:
size = 2;
@@ -300,6 +303,9 @@ utf8asn1str(char **to, int type, const char *from, const char *end)
}
else {
for(outlength = 0; from < end;) {
+ int charsize;
+ unsigned int wc;
+
wc = 0;
switch(size) {
case 4:
@@ -341,96 +347,105 @@ utf8asn1str(char **to, int type, const char *from, const char *end)
return outlength;
}
+/*
+ * Convert an ASN.1 String into its UTF-8 string representation.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
static const char *string2str(int type, const char *beg, const char *end)
{
char *buf;
-
- /* Convert an ASN.1 String into its UTF-8 string representation.
- Return the dynamically allocated string, or NULL if an error occurs. */
-
if(utf8asn1str(&buf, type, beg, end) < 0)
- return (const char *) NULL;
+ return NULL;
return buf;
}
-static int encodeUint(char *buf, int n, unsigned int x)
+/*
+ * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at
+ * buf. Return the total number of encoded digits, even if larger than
+ * `buflen'.
+ */
+static size_t encodeUint(char *buf, size_t buflen, unsigned int x)
{
- int i = 0;
+ size_t i = 0;
unsigned int y = x / 10;
- /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'.
- Return the total number of encoded digits, even if larger than `n'. */
-
if(y) {
- i += encodeUint(buf, n, y);
+ i = encodeUint(buf, buflen, y);
x -= y * 10;
}
- if(i < n)
+ if(i < buflen)
buf[i] = (char) ('0' + x);
i++;
- if(i < n)
+ if(i < buflen)
buf[i] = '\0'; /* Store a terminator if possible. */
return i;
}
-static int encodeOID(char *buf, int n, const char *beg, const char *end)
+/*
+ * Convert an ASN.1 OID into its dotted string representation.
+ * Store the result in th `n'-byte buffer at `buf'.
+ * Return the converted string length, or 0 on errors.
+ */
+static size_t encodeOID(char *buf, size_t buflen,
+ const char *beg, const char *end)
{
- int i = 0;
+ size_t i;
unsigned int x;
unsigned int y;
- /* Convert an ASN.1 OID into its dotted string representation.
- Store the result in th `n'-byte buffer at `buf'.
- Return the converted string length, or -1 if an error occurs. */
-
/* Process the first two numbers. */
y = *(const unsigned char *) beg++;
x = y / 40;
y -= x * 40;
- i += encodeUint(buf + i, n - i, x);
- if(i < n)
+ i = encodeUint(buf, buflen, x);
+ if(i < buflen)
buf[i] = '.';
i++;
- i += encodeUint(buf + i, n - i, y);
+ if(i >= buflen)
+ i += encodeUint(NULL, 0, y);
+ else
+ i += encodeUint(buf + i, buflen - i, y);
/* Process the trailing numbers. */
while(beg < end) {
- if(i < n)
+ if(i < buflen)
buf[i] = '.';
i++;
x = 0;
do {
if(x & 0xFF000000)
- return -1;
+ return 0;
y = *(const unsigned char *) beg++;
x = (x << 7) | (y & 0x7F);
} while(y & 0x80);
- i += encodeUint(buf + i, n - i, x);
+ if(i >= buflen)
+ i += encodeUint(NULL, 0, x);
+ else
+ i += encodeUint(buf + i, buflen - i, x);
}
- if(i < n)
+ if(i < buflen)
buf[i] = '\0';
return i;
}
+/*
+ * Convert an ASN.1 OID into its dotted or symbolic string representation.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
+
static const char *OID2str(const char *beg, const char *end, bool symbolic)
{
- char *buf = (char *) NULL;
- const curl_OID * op;
- int n;
-
- /* Convert an ASN.1 OID into its dotted or symbolic string representation.
- Return the dynamically allocated string, or NULL if an error occurs. */
-
+ char *buf = NULL;
if(beg < end) {
- n = encodeOID((char *) NULL, -1, beg, end);
- if(n >= 0) {
- buf = malloc(n + 1);
+ size_t buflen = encodeOID(NULL, 0, beg, end);
+ if(buflen) {
+ buf = malloc(buflen + 1); /* one extra for the zero byte */
if(buf) {
- encodeOID(buf, n, beg, end);
- buf[n] = '\0';
+ encodeOID(buf, buflen, beg, end);
+ buf[buflen] = '\0';
if(symbolic) {
- op = searchOID(buf);
+ const curl_OID *op = searchOID(buf);
if(op) {
free(buf);
buf = strdup(op->textoid);
@@ -470,7 +485,7 @@ static const char *GTime2str(const char *beg, const char *end)
sec2 = fracp[-1];
break;
default:
- return (const char *) NULL;
+ return NULL;
}
/* Scan for timezone, measure fractional seconds. */
@@ -506,15 +521,16 @@ static const char *GTime2str(const char *beg, const char *end)
sep, tzl, tzp);
}
+/*
+ * Convert an ASN.1 UTC time to a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
static const char *UTime2str(const char *beg, const char *end)
{
const char *tzp;
size_t tzl;
const char *sec;
- /* Convert an ASN.1 UTC time to a printable string.
- Return the dynamically allocated string, or NULL if an error occurs. */
-
for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
;
/* Get the seconds. */
@@ -525,12 +541,12 @@ static const char *UTime2str(const char *beg, const char *end)
case 2:
break;
default:
- return (const char *) NULL;
+ return NULL;
}
/* Process timezone. */
if(tzp >= end)
- return (const char *) NULL;
+ return NULL;
if(*tzp == 'Z') {
tzp = "GMT";
end = tzp + 3;
@@ -545,13 +561,14 @@ static const char *UTime2str(const char *beg, const char *end)
tzl, tzp);
}
+/*
+ * Convert an ASN.1 element to a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
static const char *ASN1tostr(curl_asn1Element *elem, int type)
{
- /* Convert an ASN.1 element to a printable string.
- Return the dynamically allocated string, or NULL if an error occurs. */
-
if(elem->constructed)
- return (const char *) NULL; /* No conversion of structured elements. */
+ return NULL; /* No conversion of structured elements. */
if(!type)
type = elem->tag; /* Type not forced: use element tag as type. */
@@ -585,10 +602,14 @@ static const char *ASN1tostr(curl_asn1Element *elem, int type)
return string2str(type, elem->beg, elem->end);
}
- return (const char *) NULL; /* Unsupported. */
+ return NULL; /* Unsupported. */
}
-static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
+/*
+ * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
+ * `buf'. Return the total string length, even if larger than `buflen'.
+ */
+static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn)
{
curl_asn1Element rdn;
curl_asn1Element atv;
@@ -600,9 +621,6 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
const char *p3;
const char *str;
- /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
- Return the total string length, even if larger than `n'. */
-
for(p1 = dn->beg; p1 < dn->end;) {
p1 = getASN1Element(&rdn, p1, dn->end);
if(!p1)
@@ -626,7 +644,7 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
for(p3 = str; isupper(*p3); p3++)
;
for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
- if(l < n)
+ if(l < buflen)
buf[l] = *p3;
l++;
}
@@ -634,14 +652,14 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
/* Encode attribute name. */
for(p3 = str; *p3; p3++) {
- if(l < n)
+ if(l < buflen)
buf[l] = *p3;
l++;
}
free((char *) str);
/* Generate equal sign. */
- if(l < n)
+ if(l < buflen)
buf[l] = '=';
l++;
@@ -650,7 +668,7 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
if(!str)
return -1;
for(p3 = str; *p3; p3++) {
- if(l < n)
+ if(l < buflen)
buf[l] = *p3;
l++;
}
@@ -661,28 +679,30 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
return l;
}
+/*
+ * Convert an ASN.1 distinguished name into a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
static const char *DNtostr(curl_asn1Element *dn)
{
- char *buf = (char *) NULL;
- ssize_t n = encodeDN(buf, 0, dn);
-
- /* Convert an ASN.1 distinguished name into a printable string.
- Return the dynamically allocated string, or NULL if an error occurs. */
+ char *buf = NULL;
+ ssize_t buflen = encodeDN(NULL, 0, dn);
- if(n >= 0) {
- buf = malloc(n + 1);
+ if(buflen >= 0) {
+ buf = malloc(buflen + 1);
if(buf) {
- encodeDN(buf, n + 1, dn);
- buf[n] = '\0';
+ encodeDN(buf, buflen + 1, dn);
+ buf[buflen] = '\0';
}
}
- return (const char *) buf;
+ return buf;
}
/*
- * X509 parser.
+ * ASN.1 parse an X509 certificate into structure subfields.
+ * Syntax is assumed to have already been checked by the SSL backend.
+ * See RFC 5280.
*/
-
int Curl_parseX509(curl_X509certificate *cert,
const char *beg, const char *end)
{
@@ -691,10 +711,6 @@ int Curl_parseX509(curl_X509certificate *cert,
const char *ccp;
static const char defaultVersion = 0; /* v1. */
- /* ASN.1 parse an X509 certificate into structure subfields.
- Syntax is assumed to have already been checked by the SSL backend.
- See RFC 5280. */
-
cert->certificate.header = NULL;
cert->certificate.beg = beg;
cert->certificate.end = end;
@@ -801,13 +817,14 @@ int Curl_parseX509(curl_X509certificate *cert,
return 0;
}
+
+/*
+ * Copy at most 64-characters, terminate with a newline and returns the
+ * effective number of stored characters.
+ */
static size_t copySubstring(char *to, const char *from)
{
size_t i;
-
- /* Copy at most 64-characters, terminate with a newline and returns the
- effective number of stored characters. */
-
for(i = 0; i < 64; i++) {
to[i] = *from;
if(!*from++)
@@ -861,9 +878,6 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
curl_asn1Element elem;
curl_asn1Element pk;
const char *p;
- const char *q;
- unsigned long len;
- unsigned int i;
/* Generate all information records for the public key. */
@@ -872,6 +886,9 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
return;
if(strcasecompare(algo, "rsaEncryption")) {
+ const char *q;
+ unsigned long len;
+
p = getASN1Element(&elem, pk.beg, pk.end);
if(!p)
return;
@@ -880,9 +897,11 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
for(q = elem.beg; !*q && q < elem.end; q++)
;
len = (unsigned long)((elem.end - q) * 8);
- if(len)
+ if(len) {
+ unsigned int i;
for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
len--;
+ }
if(len > 32)
elem.beg = q; /* Strip leading zero bytes. */
if(!certnum)
@@ -1040,8 +1059,6 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn,
do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
free((char *) ccp);
-/* TODO: extensions. */
-
/* Signature. */
ccp = ASN1tostr(&cert.signature, 0);
if(!ccp)
@@ -1104,15 +1121,15 @@ static const char *checkOID(const char *beg, const char *end,
ccp = getASN1Element(&e, beg, end);
if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
- return (const char *) NULL;
+ return NULL;
p = OID2str(e.beg, e.end, FALSE);
if(!p)
- return (const char *) NULL;
+ return NULL;
matched = !strcmp(p, oid);
free((char *) p);
- return matched? ccp: (const char *) NULL;
+ return matched? ccp: NULL;
}
CURLcode Curl_verifyhost(struct connectdata *conn,
diff --git a/Utilities/cmexpat/CMakeLists.txt b/Utilities/cmexpat/CMakeLists.txt
index 470fcba99..13eb56dd4 100644
--- a/Utilities/cmexpat/CMakeLists.txt
+++ b/Utilities/cmexpat/CMakeLists.txt
@@ -1,6 +1,6 @@
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmexpat/ConfigureChecks.cmake b/Utilities/cmexpat/ConfigureChecks.cmake
index 057cfa58d..b2edc3e0a 100644
--- a/Utilities/cmexpat/ConfigureChecks.cmake
+++ b/Utilities/cmexpat/ConfigureChecks.cmake
@@ -1,6 +1,7 @@
+include(CheckCCompilerFlag)
+include(CheckCSourceCompiles)
include(CheckIncludeFile)
include(CheckIncludeFiles)
-include(CheckFunctionExists)
include(CheckSymbolExists)
include(TestBigEndian)
@@ -16,10 +17,21 @@ check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
check_include_file("unistd.h" HAVE_UNISTD_H)
-check_function_exists("getpagesize" HAVE_GETPAGESIZE)
-check_function_exists("bcopy" HAVE_BCOPY)
-check_symbol_exists("memmove" "string.h" HAVE_MEMMOVE)
-check_function_exists("mmap" HAVE_MMAP)
+check_symbol_exists("getpagesize" "unistd.h" HAVE_GETPAGESIZE)
+check_symbol_exists("mmap" "sys/mman.h" HAVE_MMAP)
+check_symbol_exists("getrandom" "sys/random.h" HAVE_GETRANDOM)
+
+if(USE_libbsd)
+ set(CMAKE_REQUIRED_LIBRARIES "${LIB_BSD}")
+ set(_bsd "bsd/")
+else()
+ set(_bsd "")
+endif()
+check_symbol_exists("arc4random_buf" "${_bsd}stdlib.h" HAVE_ARC4RANDOM_BUF)
+if(NOT HAVE_ARC4RANDOM_BUF)
+ check_symbol_exists("arc4random" "${_bsd}stdlib.h" HAVE_ARC4RANDOM)
+endif()
+set(CMAKE_REQUIRED_LIBRARIES)
#/* Define to 1 if you have the ANSI C header files. */
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
@@ -40,5 +52,18 @@ else(HAVE_SYS_TYPES_H)
set(SIZE_T "unsigned")
endif(HAVE_SYS_TYPES_H)
+check_c_source_compiles("
+ #include <stdlib.h> /* for NULL */
+ #include <unistd.h> /* for syscall */
+ #include <sys/syscall.h> /* for SYS_getrandom */
+ int main() {
+ syscall(SYS_getrandom, NULL, 0, 0);
+ return 0;
+ }"
+ HAVE_SYSCALL_GETRANDOM)
+
configure_file(expat_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h")
add_definitions(-DHAVE_EXPAT_CONFIG_H)
+
+check_c_compiler_flag("-fno-strict-aliasing" FLAG_NO_STRICT_ALIASING)
+check_c_compiler_flag("-fvisibility=hidden" FLAG_VISIBILITY)
diff --git a/Utilities/cmexpat/README.md b/Utilities/cmexpat/README.md
index 0a1777e7e..fd3911ebc 100644
--- a/Utilities/cmexpat/README.md
+++ b/Utilities/cmexpat/README.md
@@ -1,4 +1,9 @@
-# Expat, Release 2.2.3
+[![Travis CI Build Status](https://travis-ci.org/libexpat/libexpat.svg?branch=master)](https://travis-ci.org/libexpat/libexpat)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/libexpat/libexpat?svg=true)](https://ci.appveyor.com/project/libexpat/libexpat)
+[![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
+
+
+# Expat, Release 2.2.7
This is Expat, a C library for parsing XML, started by
[James Clark](https://en.wikipedia.org/wiki/James_Clark_(programmer)) in 1997.
@@ -72,47 +77,43 @@ the directories into which things will be installed.
If you are interested in building Expat to provide document
information in UTF-16 encoding rather than the default UTF-8, follow
-these instructions (after having run `make distclean`):
+these instructions (after having run `make distclean`).
+Please note that we configure with `--without-xmlwf` as xmlwf does not
+support this mode of compilation (yet):
+
+1. Mass-patch `Makefile.am` files to use `libexpatw.la` for a library name:
+ <br/>
+ `find -name Makefile.am -exec sed
+ -e 's,libexpat\.la,libexpatw.la,'
+ -e 's,libexpat_la,libexpatw_la,'
+ -i {} +`
+
+1. Run `automake` to re-write `Makefile.in` files:<br/>
+ `automake`
1. For UTF-16 output as unsigned short (and version/error strings as char),
run:<br/>
- `./configure CPPFLAGS=-DXML_UNICODE`<br/>
+ `./configure CPPFLAGS=-DXML_UNICODE --without-xmlwf`<br/>
For UTF-16 output as `wchar_t` (incl. version/error strings), run:<br/>
- `./configure CFLAGS="-g -O2 -fshort-wchar" CPPFLAGS=-DXML_UNICODE_WCHAR_T`
+ `./configure CFLAGS="-g -O2 -fshort-wchar" CPPFLAGS=-DXML_UNICODE_WCHAR_T
+ --without-xmlwf`
<br/>Note: The latter requires libc compiled with `-fshort-wchar`, as well.
-1. Edit `Makefile`, changing:<br/>
- `LIBRARY = libexpat.la`<br/>
- to:<br/>
- `LIBRARY = libexpatw.la`<br/>
- (Note the additional "w" in the library name.)
+1. Run `make` (which excludes xmlwf).
-1. Run `make buildlib` (which builds the library only).
- Or, to save step 2, run `make buildlib LIBRARY=libexpatw.la`.
+1. Run `make install` (again, excludes xmlwf).
-1. Run `make installlib` (which installs the library only).
- Or, if step 2 was omitted, run `make installlib LIBRARY=libexpatw.la`.
-
-Using `DESTDIR` or `INSTALL_ROOT` is enabled, with `INSTALL_ROOT` being the
-default value for `DESTDIR`, and the rest of the make file using only
-`DESTDIR`. It works as follows:
+Using `DESTDIR` is supported. It works as follows:
```console
make install DESTDIR=/path/to/image
```
-overrides the in-makefile set `DESTDIR`, while both
-
-```console
-INSTALL_ROOT=/path/to/image make install
-make install INSTALL_ROOT=/path/to/image
-```
+overrides the in-makefile set `DESTDIR`, because variable-setting priority is
-use `DESTDIR=$(INSTALL_ROOT)`, even if `DESTDIR` eventually is defined in the
-environment, because variable-setting priority is
1. commandline
-2. in-makefile
-3. environment
+1. in-makefile
+1. environment
Note: This only applies to the Expat library itself, building UTF-16 versions
of xmlwf and the tests is currently not supported.
diff --git a/Utilities/cmexpat/expat_config.h.cmake b/Utilities/cmexpat/expat_config.h.cmake
index ad540d604..899d3a615 100644
--- a/Utilities/cmexpat/expat_config.h.cmake
+++ b/Utilities/cmexpat/expat_config.h.cmake
@@ -1,10 +1,13 @@
-/* expat_config.h.in. Generated from configure.in by autoheader. */
+/* expat_config.h.cmake. Based upon generated expat_config.h.in. */
/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
#cmakedefine BYTEORDER @BYTEORDER@
-/* Define to 1 if you have the `bcopy' function. */
-#cmakedefine HAVE_BCOPY
+/* Define to 1 if you have the `arc4random' function. */
+#cmakedefine HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#cmakedefine HAVE_ARC4RANDOM_BUF
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H
@@ -15,11 +18,14 @@
/* Define to 1 if you have the `getpagesize' function. */
#cmakedefine HAVE_GETPAGESIZE
+/* Define to 1 if you have the `getrandom' function. */
+#cmakedefine HAVE_GETRANDOM
+
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H
-/* Define to 1 if you have the `memmove' function. */
-#cmakedefine HAVE_MEMMOVE
+/* Define to 1 if you have the `bsd' library (-lbsd). */
+#cmakedefine HAVE_LIBBSD
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H
@@ -39,6 +45,9 @@
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H
+/* Define to 1 if you have `syscall' and `SYS_getrandom'. */
+#cmakedefine HAVE_SYSCALL_GETRANDOM
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
@@ -64,6 +73,17 @@
/* Define to make XML Namespaces functionality available. */
/* #undef XML_NS */
+#if ! defined(_WIN32)
+/* Define to extract entropy from /dev/urandom. */
+#cmakedefine XML_DEV_URANDOM
+#endif
+
+/* Define to use UTF-16 chars (two bytes). */
+#cmakedefine XML_UNICODE
+
+/* Define to use wchar_t as UTF-16 char type instead of unsigned short. */
+#cmakedefine XML_UNICODE_WCHAR_T
+
/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
#ifdef _MSC_VER
# define __func__ __FUNCTION__
diff --git a/Utilities/cmexpat/lib/ascii.h b/Utilities/cmexpat/lib/ascii.h
index d10530b09..c3587e573 100644
--- a/Utilities/cmexpat/lib/ascii.h
+++ b/Utilities/cmexpat/lib/ascii.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define ASCII_A 0x41
diff --git a/Utilities/cmexpat/lib/asciitab.h b/Utilities/cmexpat/lib/asciitab.h
index 79a15c28c..2f59fd929 100644
--- a/Utilities/cmexpat/lib/asciitab.h
+++ b/Utilities/cmexpat/lib/asciitab.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
diff --git a/Utilities/cmexpat/lib/expat.h b/Utilities/cmexpat/lib/expat.h
index 7e5bbb7e3..c050f1d91 100644
--- a/Utilities/cmexpat/lib/expat.h
+++ b/Utilities/cmexpat/lib/expat.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef Expat_INCLUDED
@@ -236,7 +264,7 @@ XML_ParserCreate_MM(const XML_Char *encoding,
const XML_Char *namespaceSeparator);
/* Prepare a parser object to be re-used. This is particularly
- valuable when memory allocation overhead is disproportionatly high,
+ valuable when memory allocation overhead is disproportionately high,
such as when a large number of small documnents need to be parsed.
All handlers are cleared from the parser, except for the
unknownEncodingHandler. The parser's external state is re-initialized
@@ -1048,7 +1076,7 @@ XML_GetFeatureList(void);
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 3
+#define XML_MICRO_VERSION 7
#ifdef __cplusplus
}
diff --git a/Utilities/cmexpat/lib/expat_external.h b/Utilities/cmexpat/lib/expat_external.h
index d60eeccfb..4e14470e8 100644
--- a/Utilities/cmexpat/lib/expat_external.h
+++ b/Utilities/cmexpat/lib/expat_external.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef Expat_External_INCLUDED
@@ -8,7 +36,7 @@
/* External API definitions */
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
-#define XML_USE_MSC_EXTENSIONS 1
+# define XML_USE_MSC_EXTENSIONS 1
#endif
/* Expat tries very hard to make the API boundary very specifically
@@ -34,11 +62,11 @@
system headers may assume the cdecl convention.
*/
#ifndef XMLCALL
-#if defined(_MSC_VER)
-#define XMLCALL __cdecl
-#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
-#define XMLCALL __attribute__((cdecl))
-#else
+# if defined(_MSC_VER)
+# define XMLCALL __cdecl
+# elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
+# define XMLCALL __attribute__((cdecl))
+# else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
@@ -49,43 +77,47 @@
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
-#define XMLCALL
-#endif
+# define XMLCALL
+# endif
#endif /* not defined XMLCALL */
/* Build within CMake hard-codes use of a static library. */
#define XML_STATIC
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
-#ifndef XML_BUILDING_EXPAT
+# ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
-#ifdef XML_USE_MSC_EXTENSIONS
-#define XMLIMPORT __declspec(dllimport)
-#endif
+# ifdef XML_USE_MSC_EXTENSIONS
+# define XMLIMPORT __declspec(dllimport)
+# endif
-#endif
+# endif
#endif /* not defined XML_STATIC */
-#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
-#define XMLIMPORT __attribute__ ((visibility ("default")))
+#ifndef XML_ENABLE_VISIBILITY
+# define XML_ENABLE_VISIBILITY 0
+#endif
+
+#if !defined(XMLIMPORT) && XML_ENABLE_VISIBILITY
+# define XMLIMPORT __attribute__ ((visibility ("default")))
#endif
/* If we didn't define it above, define it away: */
#ifndef XMLIMPORT
-#define XMLIMPORT
+# define XMLIMPORT
#endif
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
-#define XML_ATTR_MALLOC __attribute__((__malloc__))
+# define XML_ATTR_MALLOC __attribute__((__malloc__))
#else
-#define XML_ATTR_MALLOC
+# define XML_ATTR_MALLOC
#endif
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
-#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
#else
-#define XML_ATTR_ALLOC_SIZE(x)
+# define XML_ATTR_ALLOC_SIZE(x)
#endif
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
@@ -95,33 +127,35 @@ extern "C" {
#endif
#ifdef XML_UNICODE_WCHAR_T
-# define XML_UNICODE
+# ifndef XML_UNICODE
+# define XML_UNICODE
+# endif
# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
# endif
#endif
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
-#ifdef XML_UNICODE_WCHAR_T
+# ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
-#else
+# else
typedef unsigned short XML_Char;
typedef char XML_LChar;
-#endif /* XML_UNICODE_WCHAR_T */
+# endif /* XML_UNICODE_WCHAR_T */
#else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE */
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+# if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
typedef __int64 XML_Index;
typedef unsigned __int64 XML_Size;
-#else
+# else
typedef long long XML_Index;
typedef unsigned long long XML_Size;
-#endif
+# endif
#else
typedef long XML_Index;
typedef unsigned long XML_Size;
diff --git a/Utilities/cmexpat/lib/iasciitab.h b/Utilities/cmexpat/lib/iasciitab.h
index 24a1d5ccc..ce4a4bf7e 100644
--- a/Utilities/cmexpat/lib/iasciitab.h
+++ b/Utilities/cmexpat/lib/iasciitab.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
diff --git a/Utilities/cmexpat/lib/internal.h b/Utilities/cmexpat/lib/internal.h
index 94cb98e15..dc4ef0c7e 100644
--- a/Utilities/cmexpat/lib/internal.h
+++ b/Utilities/cmexpat/lib/internal.h
@@ -18,6 +18,35 @@
Note: Use of these macros is based on judgement, not hard rules,
and therefore subject to change.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
@@ -86,8 +115,13 @@ extern "C" {
#endif
+#ifdef XML_ENABLE_VISIBILITY
+#if XML_ENABLE_VISIBILITY
+__attribute__ ((visibility ("default")))
+#endif
+#endif
void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
+_INTERNAL_trim_to_complete_utf8_characters(const char * from, const char ** fromLimRef);
#ifdef __cplusplus
diff --git a/Utilities/cmexpat/lib/latin1tab.h b/Utilities/cmexpat/lib/latin1tab.h
index 53c25d76b..95dfa52b1 100644
--- a/Utilities/cmexpat/lib/latin1tab.h
+++ b/Utilities/cmexpat/lib/latin1tab.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/Utilities/cmexpat/lib/loadlibrary.c b/Utilities/cmexpat/lib/loadlibrary.c
index ffce86839..35fdf98bc 100644
--- a/Utilities/cmexpat/lib/loadlibrary.c
+++ b/Utilities/cmexpat/lib/loadlibrary.c
@@ -6,8 +6,10 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2016 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2017, Expat development team
*
* All rights reserved.
+ * Licensed under the MIT license:
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -82,7 +84,7 @@ HMODULE _Expat_LoadLibrary(LPCTSTR filename)
/* Get a handle to kernel32 so we can access it's functions at runtime */
HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
if(!hKernel32)
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
/* Attempt to find LoadLibraryEx() which is only available on Windows 2000
and above */
diff --git a/Utilities/cmexpat/lib/nametab.h b/Utilities/cmexpat/lib/nametab.h
index b05e62c77..bfa2bd38c 100644
--- a/Utilities/cmexpat/lib/nametab.h
+++ b/Utilities/cmexpat/lib/nametab.h
@@ -1,3 +1,35 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
static const unsigned namingBitmap[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
diff --git a/Utilities/cmexpat/lib/siphash.h b/Utilities/cmexpat/lib/siphash.h
index 1684b251d..3caabebe2 100644
--- a/Utilities/cmexpat/lib/siphash.h
+++ b/Utilities/cmexpat/lib/siphash.h
@@ -11,6 +11,12 @@
* --------------------------------------------------------------------------
* HISTORY:
*
+ * 2018-07-08 (Anton Maklakov)
+ * - Add "fall through" markers for GCC's -Wimplicit-fallthrough
+ *
+ * 2017-11-03 (Sebastian Pipping)
+ * - Hide sip_tobin and sip_binof unless SIPHASH_TOBIN macro is defined
+ *
* 2017-07-25 (Vadim Zeitlin)
* - Fix use of SIPHASH_MAIN macro
*
@@ -154,6 +160,8 @@ static struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
} /* sip_tokey() */
+#ifdef SIPHASH_TOBIN
+
#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
static void *sip_tobin(void *dst, uint64_t u64) {
@@ -161,6 +169,8 @@ static void *sip_tobin(void *dst, uint64_t u64) {
return dst;
} /* sip_tobin() */
+#endif /* SIPHASH_TOBIN */
+
static void sip_round(struct siphash *H, const int rounds) {
int i;
@@ -234,12 +244,19 @@ static uint64_t sip24_final(struct siphash *H) {
switch (left) {
case 7: b |= (uint64_t)H->buf[6] << 48;
+ /* fall through */
case 6: b |= (uint64_t)H->buf[5] << 40;
+ /* fall through */
case 5: b |= (uint64_t)H->buf[4] << 32;
+ /* fall through */
case 4: b |= (uint64_t)H->buf[3] << 24;
+ /* fall through */
case 3: b |= (uint64_t)H->buf[2] << 16;
+ /* fall through */
case 2: b |= (uint64_t)H->buf[1] << 8;
+ /* fall through */
case 1: b |= (uint64_t)H->buf[0] << 0;
+ /* fall through */
case 0: break;
}
diff --git a/Utilities/cmexpat/lib/utf8tab.h b/Utilities/cmexpat/lib/utf8tab.h
index 7bb3e7760..fa0bed6f5 100644
--- a/Utilities/cmexpat/lib/utf8tab.h
+++ b/Utilities/cmexpat/lib/utf8tab.h
@@ -1,7 +1,34 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
-*/
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
diff --git a/Utilities/cmexpat/lib/winconfig.h b/Utilities/cmexpat/lib/winconfig.h
index c9dbfea85..1af28822c 100644
--- a/Utilities/cmexpat/lib/winconfig.h
+++ b/Utilities/cmexpat/lib/winconfig.h
@@ -1,10 +1,33 @@
-/*================================================================
-** Copyright 2000, Clark Cooper
-** All rights reserved.
-**
-** This is free software. You are permitted to copy, distribute, or modify
-** it under the terms of the MIT/X license (contained in the COPYING file
-** with this distribution.)
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WINCONFIG_H
@@ -30,10 +53,6 @@
/* we will assume all Windows platforms are little endian */
#define BYTEORDER 1234
-/* Windows has memmove() available. */
-#define HAVE_MEMMOVE
-
-
#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
#if defined(_MSC_VER)
diff --git a/Utilities/cmexpat/lib/xmlparse.c b/Utilities/cmexpat/lib/xmlparse.c
index b703e61a0..9c0987f4f 100644
--- a/Utilities/cmexpat/lib/xmlparse.c
+++ b/Utilities/cmexpat/lib/xmlparse.c
@@ -1,7 +1,33 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
-
- 101bfd65d1ff3d1511cf6671e6aae65f82cd97df6f4da137d46d510731830ad9 (2.2.3+)
+/* 69df5be70289a11fb834869ce4a91c23c1d9dd04baffcbd10e86742d149a080c (2.2.7+)
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if !defined(_GNU_SOURCE)
@@ -80,9 +106,6 @@
If insist on not using any of these, bypass this error by defining \
XML_POOR_ENTROPY; you have been warned. \
\
- For CMake, one way to pass the define is: \
- cmake -DCMAKE_C_FLAGS="-pipe -O2 -DHAVE_SYSCALL_GETRANDOM" . \
- \
If you have reasons to patch this detection code away or need changes \
to the build system, please open a bug. Thank you!
#endif
@@ -138,14 +161,8 @@ typedef char ICHAR;
/* Round up n to be a multiple of sz, where sz is a power of 2. */
#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
-/* Handle the case where memmove() doesn't exist. */
-#ifndef HAVE_MEMMOVE
-#ifdef HAVE_BCOPY
-#define memmove(d,s,l) bcopy((s),(d),(l))
-#else
-#error memmove does not exist on this platform, nor is a substitute available
-#endif /* HAVE_BCOPY */
-#endif /* HAVE_MEMMOVE */
+/* Do safe (NULL-aware) pointer arithmetic */
+#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
#include "internal.h"
#include "xmltok.h"
@@ -447,7 +464,7 @@ setContext(XML_Parser parser, const XML_Char *context);
static void FASTCALL normalizePublicId(XML_Char *s);
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
-/* do not call if parentParser != NULL */
+/* do not call if m_parentParser != NULL */
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
static void
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
@@ -519,7 +536,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName);
: ((*((pool)->ptr)++ = c), 1))
struct XML_ParserStruct {
- /* The first member must be userData so that the XML_GetUserData
+ /* The first member must be m_userData so that the XML_GetUserData
macro works. */
void *m_userData;
void *m_handlerArg;
@@ -529,7 +546,7 @@ struct XML_ParserStruct {
const char *m_bufferPtr;
/* past last character to be parsed */
char *m_bufferEnd;
- /* allocated end of buffer */
+ /* allocated end of m_buffer */
const char *m_bufferLim;
XML_Index m_parseEndByteIndex;
const char *m_parseEndPtr;
@@ -621,113 +638,10 @@ struct XML_ParserStruct {
unsigned long m_hash_secret_salt;
};
-#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
-#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
-#define FREE(p) (parser->m_mem.free_fcn((p)))
-
-#define userData (parser->m_userData)
-#define handlerArg (parser->m_handlerArg)
-#define startElementHandler (parser->m_startElementHandler)
-#define endElementHandler (parser->m_endElementHandler)
-#define characterDataHandler (parser->m_characterDataHandler)
-#define processingInstructionHandler \
- (parser->m_processingInstructionHandler)
-#define commentHandler (parser->m_commentHandler)
-#define startCdataSectionHandler \
- (parser->m_startCdataSectionHandler)
-#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
-#define defaultHandler (parser->m_defaultHandler)
-#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
-#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
-#define unparsedEntityDeclHandler \
- (parser->m_unparsedEntityDeclHandler)
-#define notationDeclHandler (parser->m_notationDeclHandler)
-#define startNamespaceDeclHandler \
- (parser->m_startNamespaceDeclHandler)
-#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
-#define notStandaloneHandler (parser->m_notStandaloneHandler)
-#define externalEntityRefHandler \
- (parser->m_externalEntityRefHandler)
-#define externalEntityRefHandlerArg \
- (parser->m_externalEntityRefHandlerArg)
-#define internalEntityRefHandler \
- (parser->m_internalEntityRefHandler)
-#define skippedEntityHandler (parser->m_skippedEntityHandler)
-#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
-#define elementDeclHandler (parser->m_elementDeclHandler)
-#define attlistDeclHandler (parser->m_attlistDeclHandler)
-#define entityDeclHandler (parser->m_entityDeclHandler)
-#define xmlDeclHandler (parser->m_xmlDeclHandler)
-#define encoding (parser->m_encoding)
-#define initEncoding (parser->m_initEncoding)
-#define internalEncoding (parser->m_internalEncoding)
-#define unknownEncodingMem (parser->m_unknownEncodingMem)
-#define unknownEncodingData (parser->m_unknownEncodingData)
-#define unknownEncodingHandlerData \
- (parser->m_unknownEncodingHandlerData)
-#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
-#define protocolEncodingName (parser->m_protocolEncodingName)
-#define ns (parser->m_ns)
-#define ns_triplets (parser->m_ns_triplets)
-#define prologState (parser->m_prologState)
-#define processor (parser->m_processor)
-#define errorCode (parser->m_errorCode)
-#define eventPtr (parser->m_eventPtr)
-#define eventEndPtr (parser->m_eventEndPtr)
-#define positionPtr (parser->m_positionPtr)
-#define position (parser->m_position)
-#define openInternalEntities (parser->m_openInternalEntities)
-#define freeInternalEntities (parser->m_freeInternalEntities)
-#define defaultExpandInternalEntities \
- (parser->m_defaultExpandInternalEntities)
-#define tagLevel (parser->m_tagLevel)
-#define buffer (parser->m_buffer)
-#define bufferPtr (parser->m_bufferPtr)
-#define bufferEnd (parser->m_bufferEnd)
-#define parseEndByteIndex (parser->m_parseEndByteIndex)
-#define parseEndPtr (parser->m_parseEndPtr)
-#define bufferLim (parser->m_bufferLim)
-#define dataBuf (parser->m_dataBuf)
-#define dataBufEnd (parser->m_dataBufEnd)
-#define _dtd (parser->m_dtd)
-#define curBase (parser->m_curBase)
-#define declEntity (parser->m_declEntity)
-#define doctypeName (parser->m_doctypeName)
-#define doctypeSysid (parser->m_doctypeSysid)
-#define doctypePubid (parser->m_doctypePubid)
-#define declAttributeType (parser->m_declAttributeType)
-#define declNotationName (parser->m_declNotationName)
-#define declNotationPublicId (parser->m_declNotationPublicId)
-#define declElementType (parser->m_declElementType)
-#define declAttributeId (parser->m_declAttributeId)
-#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
-#define declAttributeIsId (parser->m_declAttributeIsId)
-#define freeTagList (parser->m_freeTagList)
-#define freeBindingList (parser->m_freeBindingList)
-#define inheritedBindings (parser->m_inheritedBindings)
-#define tagStack (parser->m_tagStack)
-#define atts (parser->m_atts)
-#define attsSize (parser->m_attsSize)
-#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
-#define idAttIndex (parser->m_idAttIndex)
-#define nsAtts (parser->m_nsAtts)
-#define nsAttsVersion (parser->m_nsAttsVersion)
-#define nsAttsPower (parser->m_nsAttsPower)
-#define attInfo (parser->m_attInfo)
-#define tempPool (parser->m_tempPool)
-#define temp2Pool (parser->m_temp2Pool)
-#define groupConnector (parser->m_groupConnector)
-#define groupSize (parser->m_groupSize)
-#define namespaceSeparator (parser->m_namespaceSeparator)
-#define parentParser (parser->m_parentParser)
-#define ps_parsing (parser->m_parsingStatus.parsing)
-#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
-#ifdef XML_DTD
-#define isParamEntity (parser->m_isParamEntity)
-#define useForeignDTD (parser->m_useForeignDTD)
-#define paramEntityParsing (parser->m_paramEntityParsing)
-#endif /* XML_DTD */
-#define hash_secret_salt (parser->m_hash_secret_salt)
+#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(parser, p) (parser->m_mem.free_fcn((p)))
+
XML_Parser XMLCALL
XML_ParserCreate(const XML_Char *encodingName)
@@ -753,6 +667,9 @@ static const XML_Char implicitContext[] = {
};
+/* To avoid warnings about unused functions: */
+#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
+
#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
/* Obtain entropy on Linux 3.17+ */
@@ -818,8 +735,10 @@ writeRandomBytes_dev_urandom(void * target, size_t count) {
#endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
-#if defined(HAVE_ARC4RANDOM)
+#if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF)
static void
writeRandomBytes_arc4random(void * target, size_t count) {
@@ -837,7 +756,7 @@ writeRandomBytes_arc4random(void * target, size_t count) {
}
}
-#endif /* defined(HAVE_ARC4RANDOM) */
+#endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */
#ifdef _WIN32
@@ -919,6 +838,8 @@ generate_hash_secret_salt(XML_Parser parser)
{
unsigned long entropy;
(void)parser;
+
+ /* "Failproof" high quality providers: */
#if defined(HAVE_ARC4RANDOM_BUF)
arc4random_buf(&entropy, sizeof(entropy));
return ENTROPY_DEBUG("arc4random_buf", entropy);
@@ -967,9 +888,9 @@ static XML_Bool /* only valid for root parser */
startParsing(XML_Parser parser)
{
/* hash functions must be initialized before setContext() is called */
- if (hash_secret_salt == 0)
- hash_secret_salt = generate_hash_secret_salt(parser);
- if (ns) {
+ if (parser->m_hash_secret_salt == 0)
+ parser->m_hash_secret_salt = generate_hash_secret_salt(parser);
+ if (parser->m_ns) {
/* implicit context only set for root parser, since child
parsers (i.e. external entity parsers) will inherit it
*/
@@ -1019,85 +940,85 @@ parserCreate(const XML_Char *encodingName,
if (!parser)
return parser;
- buffer = NULL;
- bufferLim = NULL;
+ parser->m_buffer = NULL;
+ parser->m_bufferLim = NULL;
- attsSize = INIT_ATTS_SIZE;
- atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
- if (atts == NULL) {
- FREE(parser);
+ parser->m_attsSize = INIT_ATTS_SIZE;
+ parser->m_atts = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
+ if (parser->m_atts == NULL) {
+ FREE(parser, parser);
return NULL;
}
#ifdef XML_ATTR_INFO
- attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
- if (attInfo == NULL) {
- FREE(atts);
- FREE(parser);
+ parser->m_attInfo = (XML_AttrInfo*)MALLOC(parser, parser->m_attsSize * sizeof(XML_AttrInfo));
+ if (parser->m_attInfo == NULL) {
+ FREE(parser, parser->m_atts);
+ FREE(parser, parser);
return NULL;
}
#endif
- dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
- if (dataBuf == NULL) {
- FREE(atts);
+ parser->m_dataBuf = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (parser->m_dataBuf == NULL) {
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
- dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+ parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;
if (dtd)
- _dtd = dtd;
+ parser->m_dtd = dtd;
else {
- _dtd = dtdCreate(&parser->m_mem);
- if (_dtd == NULL) {
- FREE(dataBuf);
- FREE(atts);
+ parser->m_dtd = dtdCreate(&parser->m_mem);
+ if (parser->m_dtd == NULL) {
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
}
- freeBindingList = NULL;
- freeTagList = NULL;
- freeInternalEntities = NULL;
+ parser->m_freeBindingList = NULL;
+ parser->m_freeTagList = NULL;
+ parser->m_freeInternalEntities = NULL;
- groupSize = 0;
- groupConnector = NULL;
+ parser->m_groupSize = 0;
+ parser->m_groupConnector = NULL;
- unknownEncodingHandler = NULL;
- unknownEncodingHandlerData = NULL;
+ parser->m_unknownEncodingHandler = NULL;
+ parser->m_unknownEncodingHandlerData = NULL;
- namespaceSeparator = ASCII_EXCL;
- ns = XML_FALSE;
- ns_triplets = XML_FALSE;
+ parser->m_namespaceSeparator = ASCII_EXCL;
+ parser->m_ns = XML_FALSE;
+ parser->m_ns_triplets = XML_FALSE;
- nsAtts = NULL;
- nsAttsVersion = 0;
- nsAttsPower = 0;
+ parser->m_nsAtts = NULL;
+ parser->m_nsAttsVersion = 0;
+ parser->m_nsAttsPower = 0;
- protocolEncodingName = NULL;
+ parser->m_protocolEncodingName = NULL;
- poolInit(&tempPool, &(parser->m_mem));
- poolInit(&temp2Pool, &(parser->m_mem));
+ poolInit(&parser->m_tempPool, &(parser->m_mem));
+ poolInit(&parser->m_temp2Pool, &(parser->m_mem));
parserInit(parser, encodingName);
- if (encodingName && !protocolEncodingName) {
+ if (encodingName && !parser->m_protocolEncodingName) {
XML_ParserFree(parser);
return NULL;
}
if (nameSep) {
- ns = XML_TRUE;
- internalEncoding = XmlGetInternalEncodingNS();
- namespaceSeparator = *nameSep;
+ parser->m_ns = XML_TRUE;
+ parser->m_internalEncoding = XmlGetInternalEncodingNS();
+ parser->m_namespaceSeparator = *nameSep;
}
else {
- internalEncoding = XmlGetInternalEncoding();
+ parser->m_internalEncoding = XmlGetInternalEncoding();
}
return parser;
@@ -1106,85 +1027,85 @@ parserCreate(const XML_Char *encodingName,
static void
parserInit(XML_Parser parser, const XML_Char *encodingName)
{
- processor = prologInitProcessor;
- XmlPrologStateInit(&prologState);
+ parser->m_processor = prologInitProcessor;
+ XmlPrologStateInit(&parser->m_prologState);
if (encodingName != NULL) {
- protocolEncodingName = copyString(encodingName, &(parser->m_mem));
- }
- curBase = NULL;
- XmlInitEncoding(&initEncoding, &encoding, 0);
- userData = NULL;
- handlerArg = NULL;
- startElementHandler = NULL;
- endElementHandler = NULL;
- characterDataHandler = NULL;
- processingInstructionHandler = NULL;
- commentHandler = NULL;
- startCdataSectionHandler = NULL;
- endCdataSectionHandler = NULL;
- defaultHandler = NULL;
- startDoctypeDeclHandler = NULL;
- endDoctypeDeclHandler = NULL;
- unparsedEntityDeclHandler = NULL;
- notationDeclHandler = NULL;
- startNamespaceDeclHandler = NULL;
- endNamespaceDeclHandler = NULL;
- notStandaloneHandler = NULL;
- externalEntityRefHandler = NULL;
- externalEntityRefHandlerArg = parser;
- skippedEntityHandler = NULL;
- elementDeclHandler = NULL;
- attlistDeclHandler = NULL;
- entityDeclHandler = NULL;
- xmlDeclHandler = NULL;
- bufferPtr = buffer;
- bufferEnd = buffer;
- parseEndByteIndex = 0;
- parseEndPtr = NULL;
- declElementType = NULL;
- declAttributeId = NULL;
- declEntity = NULL;
- doctypeName = NULL;
- doctypeSysid = NULL;
- doctypePubid = NULL;
- declAttributeType = NULL;
- declNotationName = NULL;
- declNotationPublicId = NULL;
- declAttributeIsCdata = XML_FALSE;
- declAttributeIsId = XML_FALSE;
- memset(&position, 0, sizeof(POSITION));
- errorCode = XML_ERROR_NONE;
- eventPtr = NULL;
- eventEndPtr = NULL;
- positionPtr = NULL;
- openInternalEntities = NULL;
- defaultExpandInternalEntities = XML_TRUE;
- tagLevel = 0;
- tagStack = NULL;
- inheritedBindings = NULL;
- nSpecifiedAtts = 0;
- unknownEncodingMem = NULL;
- unknownEncodingRelease = NULL;
- unknownEncodingData = NULL;
- parentParser = NULL;
- ps_parsing = XML_INITIALIZED;
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ }
+ parser->m_curBase = NULL;
+ XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
+ parser->m_userData = NULL;
+ parser->m_handlerArg = NULL;
+ parser->m_startElementHandler = NULL;
+ parser->m_endElementHandler = NULL;
+ parser->m_characterDataHandler = NULL;
+ parser->m_processingInstructionHandler = NULL;
+ parser->m_commentHandler = NULL;
+ parser->m_startCdataSectionHandler = NULL;
+ parser->m_endCdataSectionHandler = NULL;
+ parser->m_defaultHandler = NULL;
+ parser->m_startDoctypeDeclHandler = NULL;
+ parser->m_endDoctypeDeclHandler = NULL;
+ parser->m_unparsedEntityDeclHandler = NULL;
+ parser->m_notationDeclHandler = NULL;
+ parser->m_startNamespaceDeclHandler = NULL;
+ parser->m_endNamespaceDeclHandler = NULL;
+ parser->m_notStandaloneHandler = NULL;
+ parser->m_externalEntityRefHandler = NULL;
+ parser->m_externalEntityRefHandlerArg = parser;
+ parser->m_skippedEntityHandler = NULL;
+ parser->m_elementDeclHandler = NULL;
+ parser->m_attlistDeclHandler = NULL;
+ parser->m_entityDeclHandler = NULL;
+ parser->m_xmlDeclHandler = NULL;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer;
+ parser->m_parseEndByteIndex = 0;
+ parser->m_parseEndPtr = NULL;
+ parser->m_declElementType = NULL;
+ parser->m_declAttributeId = NULL;
+ parser->m_declEntity = NULL;
+ parser->m_doctypeName = NULL;
+ parser->m_doctypeSysid = NULL;
+ parser->m_doctypePubid = NULL;
+ parser->m_declAttributeType = NULL;
+ parser->m_declNotationName = NULL;
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeIsId = XML_FALSE;
+ memset(&parser->m_position, 0, sizeof(POSITION));
+ parser->m_errorCode = XML_ERROR_NONE;
+ parser->m_eventPtr = NULL;
+ parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
+ parser->m_openInternalEntities = NULL;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
+ parser->m_tagLevel = 0;
+ parser->m_tagStack = NULL;
+ parser->m_inheritedBindings = NULL;
+ parser->m_nSpecifiedAtts = 0;
+ parser->m_unknownEncodingMem = NULL;
+ parser->m_unknownEncodingRelease = NULL;
+ parser->m_unknownEncodingData = NULL;
+ parser->m_parentParser = NULL;
+ parser->m_parsingStatus.parsing = XML_INITIALIZED;
#ifdef XML_DTD
- isParamEntity = XML_FALSE;
- useForeignDTD = XML_FALSE;
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ parser->m_isParamEntity = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif
- hash_secret_salt = 0;
+ parser->m_hash_secret_salt = 0;
}
-/* moves list of bindings to freeBindingList */
+/* moves list of bindings to m_freeBindingList */
static void FASTCALL
moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
{
while (bindings) {
BINDING *b = bindings;
bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
}
}
@@ -1197,36 +1118,36 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
if (parser == NULL)
return XML_FALSE;
- if (parentParser)
+ if (parser->m_parentParser)
return XML_FALSE;
- /* move tagStack to freeTagList */
- tStk = tagStack;
+ /* move m_tagStack to m_freeTagList */
+ tStk = parser->m_tagStack;
while (tStk) {
TAG *tag = tStk;
tStk = tStk->parent;
- tag->parent = freeTagList;
+ tag->parent = parser->m_freeTagList;
moveToFreeBindingList(parser, tag->bindings);
tag->bindings = NULL;
- freeTagList = tag;
+ parser->m_freeTagList = tag;
}
- /* move openInternalEntities to freeInternalEntities */
- openEntityList = openInternalEntities;
+ /* move m_openInternalEntities to m_freeInternalEntities */
+ openEntityList = parser->m_openInternalEntities;
while (openEntityList) {
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
openEntityList = openEntity->next;
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
- }
- moveToFreeBindingList(parser, inheritedBindings);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- poolClear(&tempPool);
- poolClear(&temp2Pool);
- FREE((void *)protocolEncodingName);
- protocolEncodingName = NULL;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, parser->m_inheritedBindings);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ poolClear(&parser->m_tempPool);
+ poolClear(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
+ parser->m_protocolEncodingName = NULL;
parserInit(parser, encodingName);
- dtdReset(_dtd, &parser->m_mem);
+ dtdReset(parser->m_dtd, &parser->m_mem);
return XML_TRUE;
}
@@ -1239,19 +1160,19 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
XXX There's no way for the caller to determine which of the
XXX possible error cases caused the XML_STATUS_ERROR return.
*/
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_STATUS_ERROR;
/* Get rid of any previous encoding name */
- FREE((void *)protocolEncodingName);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
if (encodingName == NULL)
/* No new encoding name */
- protocolEncodingName = NULL;
+ parser->m_protocolEncodingName = NULL;
else {
/* Copy the new encoding name into allocated memory */
- protocolEncodingName = copyString(encodingName, &(parser->m_mem));
- if (!protocolEncodingName)
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ if (!parser->m_protocolEncodingName)
return XML_STATUS_ERROR;
}
return XML_STATUS_OK;
@@ -1308,44 +1229,44 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
return NULL;
/* Stash the original parser contents on the stack */
- oldDtd = _dtd;
- oldStartElementHandler = startElementHandler;
- oldEndElementHandler = endElementHandler;
- oldCharacterDataHandler = characterDataHandler;
- oldProcessingInstructionHandler = processingInstructionHandler;
- oldCommentHandler = commentHandler;
- oldStartCdataSectionHandler = startCdataSectionHandler;
- oldEndCdataSectionHandler = endCdataSectionHandler;
- oldDefaultHandler = defaultHandler;
- oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
- oldNotationDeclHandler = notationDeclHandler;
- oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
- oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
- oldNotStandaloneHandler = notStandaloneHandler;
- oldExternalEntityRefHandler = externalEntityRefHandler;
- oldSkippedEntityHandler = skippedEntityHandler;
- oldUnknownEncodingHandler = unknownEncodingHandler;
- oldElementDeclHandler = elementDeclHandler;
- oldAttlistDeclHandler = attlistDeclHandler;
- oldEntityDeclHandler = entityDeclHandler;
- oldXmlDeclHandler = xmlDeclHandler;
- oldDeclElementType = declElementType;
-
- oldUserData = userData;
- oldHandlerArg = handlerArg;
- oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
- oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+ oldDtd = parser->m_dtd;
+ oldStartElementHandler = parser->m_startElementHandler;
+ oldEndElementHandler = parser->m_endElementHandler;
+ oldCharacterDataHandler = parser->m_characterDataHandler;
+ oldProcessingInstructionHandler = parser->m_processingInstructionHandler;
+ oldCommentHandler = parser->m_commentHandler;
+ oldStartCdataSectionHandler = parser->m_startCdataSectionHandler;
+ oldEndCdataSectionHandler = parser->m_endCdataSectionHandler;
+ oldDefaultHandler = parser->m_defaultHandler;
+ oldUnparsedEntityDeclHandler = parser->m_unparsedEntityDeclHandler;
+ oldNotationDeclHandler = parser->m_notationDeclHandler;
+ oldStartNamespaceDeclHandler = parser->m_startNamespaceDeclHandler;
+ oldEndNamespaceDeclHandler = parser->m_endNamespaceDeclHandler;
+ oldNotStandaloneHandler = parser->m_notStandaloneHandler;
+ oldExternalEntityRefHandler = parser->m_externalEntityRefHandler;
+ oldSkippedEntityHandler = parser->m_skippedEntityHandler;
+ oldUnknownEncodingHandler = parser->m_unknownEncodingHandler;
+ oldElementDeclHandler = parser->m_elementDeclHandler;
+ oldAttlistDeclHandler = parser->m_attlistDeclHandler;
+ oldEntityDeclHandler = parser->m_entityDeclHandler;
+ oldXmlDeclHandler = parser->m_xmlDeclHandler;
+ oldDeclElementType = parser->m_declElementType;
+
+ oldUserData = parser->m_userData;
+ oldHandlerArg = parser->m_handlerArg;
+ oldDefaultExpandInternalEntities = parser->m_defaultExpandInternalEntities;
+ oldExternalEntityRefHandlerArg = parser->m_externalEntityRefHandlerArg;
#ifdef XML_DTD
- oldParamEntityParsing = paramEntityParsing;
- oldInEntityValue = prologState.inEntityValue;
+ oldParamEntityParsing = parser->m_paramEntityParsing;
+ oldInEntityValue = parser->m_prologState.inEntityValue;
#endif
- oldns_triplets = ns_triplets;
+ oldns_triplets = parser->m_ns_triplets;
/* Note that the new parser shares the same hash secret as the old
parser, so that dtdCopy and copyEntityTable can lookup values
from hash tables associated with either parser without us having
to worry which hash secrets each table has.
*/
- oldhash_secret_salt = hash_secret_salt;
+ oldhash_secret_salt = parser->m_hash_secret_salt;
#ifdef XML_DTD
if (!context)
@@ -1357,9 +1278,9 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
here. This makes this function more painful to follow than it
would be otherwise.
*/
- if (ns) {
+ if (parser->m_ns) {
XML_Char tmp[2];
- *tmp = namespaceSeparator;
+ *tmp = parser->m_namespaceSeparator;
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
}
else {
@@ -1369,62 +1290,62 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
if (!parser)
return NULL;
- startElementHandler = oldStartElementHandler;
- endElementHandler = oldEndElementHandler;
- characterDataHandler = oldCharacterDataHandler;
- processingInstructionHandler = oldProcessingInstructionHandler;
- commentHandler = oldCommentHandler;
- startCdataSectionHandler = oldStartCdataSectionHandler;
- endCdataSectionHandler = oldEndCdataSectionHandler;
- defaultHandler = oldDefaultHandler;
- unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
- notationDeclHandler = oldNotationDeclHandler;
- startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
- endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
- notStandaloneHandler = oldNotStandaloneHandler;
- externalEntityRefHandler = oldExternalEntityRefHandler;
- skippedEntityHandler = oldSkippedEntityHandler;
- unknownEncodingHandler = oldUnknownEncodingHandler;
- elementDeclHandler = oldElementDeclHandler;
- attlistDeclHandler = oldAttlistDeclHandler;
- entityDeclHandler = oldEntityDeclHandler;
- xmlDeclHandler = oldXmlDeclHandler;
- declElementType = oldDeclElementType;
- userData = oldUserData;
+ parser->m_startElementHandler = oldStartElementHandler;
+ parser->m_endElementHandler = oldEndElementHandler;
+ parser->m_characterDataHandler = oldCharacterDataHandler;
+ parser->m_processingInstructionHandler = oldProcessingInstructionHandler;
+ parser->m_commentHandler = oldCommentHandler;
+ parser->m_startCdataSectionHandler = oldStartCdataSectionHandler;
+ parser->m_endCdataSectionHandler = oldEndCdataSectionHandler;
+ parser->m_defaultHandler = oldDefaultHandler;
+ parser->m_unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ parser->m_notationDeclHandler = oldNotationDeclHandler;
+ parser->m_startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ parser->m_endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ parser->m_notStandaloneHandler = oldNotStandaloneHandler;
+ parser->m_externalEntityRefHandler = oldExternalEntityRefHandler;
+ parser->m_skippedEntityHandler = oldSkippedEntityHandler;
+ parser->m_unknownEncodingHandler = oldUnknownEncodingHandler;
+ parser->m_elementDeclHandler = oldElementDeclHandler;
+ parser->m_attlistDeclHandler = oldAttlistDeclHandler;
+ parser->m_entityDeclHandler = oldEntityDeclHandler;
+ parser->m_xmlDeclHandler = oldXmlDeclHandler;
+ parser->m_declElementType = oldDeclElementType;
+ parser->m_userData = oldUserData;
if (oldUserData == oldHandlerArg)
- handlerArg = userData;
+ parser->m_handlerArg = parser->m_userData;
else
- handlerArg = parser;
+ parser->m_handlerArg = parser;
if (oldExternalEntityRefHandlerArg != oldParser)
- externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
- defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
- ns_triplets = oldns_triplets;
- hash_secret_salt = oldhash_secret_salt;
- parentParser = oldParser;
+ parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ parser->m_ns_triplets = oldns_triplets;
+ parser->m_hash_secret_salt = oldhash_secret_salt;
+ parser->m_parentParser = oldParser;
#ifdef XML_DTD
- paramEntityParsing = oldParamEntityParsing;
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_paramEntityParsing = oldParamEntityParsing;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
if (context) {
#endif /* XML_DTD */
- if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+ if (!dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem)
|| !setContext(parser, context)) {
XML_ParserFree(parser);
return NULL;
}
- processor = externalEntityInitProcessor;
+ parser->m_processor = externalEntityInitProcessor;
#ifdef XML_DTD
}
else {
- /* The DTD instance referenced by _dtd is shared between the document's
+ /* The DTD instance referenced by parser->m_dtd is shared between the document's
root parser and external PE parsers, therefore one does not need to
call setContext. In addition, one also *must* not call setContext,
because this would overwrite existing prefix->binding pointers in
- _dtd with ones that get destroyed with the external PE parser.
+ parser->m_dtd with ones that get destroyed with the external PE parser.
This would leave those prefixes with dangling pointers.
*/
- isParamEntity = XML_TRUE;
- XmlPrologStateInitExternalEntity(&prologState);
- processor = externalParEntInitProcessor;
+ parser->m_isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&parser->m_prologState);
+ parser->m_processor = externalParEntInitProcessor;
}
#endif /* XML_DTD */
return parser;
@@ -1438,8 +1359,8 @@ destroyBindings(BINDING *bindings, XML_Parser parser)
if (!b)
break;
bindings = b->nextTagBinding;
- FREE(b->uri);
- FREE(b);
+ FREE(parser, b->uri);
+ FREE(parser, b);
}
}
@@ -1450,70 +1371,70 @@ XML_ParserFree(XML_Parser parser)
OPEN_INTERNAL_ENTITY *entityList;
if (parser == NULL)
return;
- /* free tagStack and freeTagList */
- tagList = tagStack;
+ /* free m_tagStack and m_freeTagList */
+ tagList = parser->m_tagStack;
for (;;) {
TAG *p;
if (tagList == NULL) {
- if (freeTagList == NULL)
+ if (parser->m_freeTagList == NULL)
break;
- tagList = freeTagList;
- freeTagList = NULL;
+ tagList = parser->m_freeTagList;
+ parser->m_freeTagList = NULL;
}
p = tagList;
tagList = tagList->parent;
- FREE(p->buf);
+ FREE(parser, p->buf);
destroyBindings(p->bindings, parser);
- FREE(p);
+ FREE(parser, p);
}
- /* free openInternalEntities and freeInternalEntities */
- entityList = openInternalEntities;
+ /* free m_openInternalEntities and m_freeInternalEntities */
+ entityList = parser->m_openInternalEntities;
for (;;) {
OPEN_INTERNAL_ENTITY *openEntity;
if (entityList == NULL) {
- if (freeInternalEntities == NULL)
+ if (parser->m_freeInternalEntities == NULL)
break;
- entityList = freeInternalEntities;
- freeInternalEntities = NULL;
+ entityList = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = NULL;
}
openEntity = entityList;
entityList = entityList->next;
- FREE(openEntity);
+ FREE(parser, openEntity);
}
- destroyBindings(freeBindingList, parser);
- destroyBindings(inheritedBindings, parser);
- poolDestroy(&tempPool);
- poolDestroy(&temp2Pool);
- FREE((void *)protocolEncodingName);
+ destroyBindings(parser->m_freeBindingList, parser);
+ destroyBindings(parser->m_inheritedBindings, parser);
+ poolDestroy(&parser->m_tempPool);
+ poolDestroy(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
#ifdef XML_DTD
/* external parameter entity parsers share the DTD structure
parser->m_dtd with the root parser, so we must not destroy it
*/
- if (!isParamEntity && _dtd)
+ if (!parser->m_isParamEntity && parser->m_dtd)
#else
- if (_dtd)
+ if (parser->m_dtd)
#endif /* XML_DTD */
- dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
- FREE((void *)atts);
+ dtdDestroy(parser->m_dtd, (XML_Bool)!parser->m_parentParser, &parser->m_mem);
+ FREE(parser, (void *)parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE((void *)attInfo);
+ FREE(parser, (void *)parser->m_attInfo);
#endif
- FREE(groupConnector);
- FREE(buffer);
- FREE(dataBuf);
- FREE(nsAtts);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- FREE(parser);
+ FREE(parser, parser->m_groupConnector);
+ FREE(parser, parser->m_buffer);
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_nsAtts);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ FREE(parser, parser);
}
void XMLCALL
XML_UseParserAsHandlerArg(XML_Parser parser)
{
if (parser != NULL)
- handlerArg = parser;
+ parser->m_handlerArg = parser;
}
enum XML_Error XMLCALL
@@ -1523,9 +1444,9 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
return XML_ERROR_INVALID_ARGUMENT;
#ifdef XML_DTD
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
- useForeignDTD = useDTD;
+ parser->m_useForeignDTD = useDTD;
return XML_ERROR_NONE;
#else
return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
@@ -1538,9 +1459,9 @@ XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
if (parser == NULL)
return;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return;
- ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+ parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
}
void XMLCALL
@@ -1548,10 +1469,10 @@ XML_SetUserData(XML_Parser parser, void *p)
{
if (parser == NULL)
return;
- if (handlerArg == userData)
- handlerArg = userData = p;
+ if (parser->m_handlerArg == parser->m_userData)
+ parser->m_handlerArg = parser->m_userData = p;
else
- userData = p;
+ parser->m_userData = p;
}
enum XML_Status XMLCALL
@@ -1560,13 +1481,13 @@ XML_SetBase(XML_Parser parser, const XML_Char *p)
if (parser == NULL)
return XML_STATUS_ERROR;
if (p) {
- p = poolCopyString(&_dtd->pool, p);
+ p = poolCopyString(&parser->m_dtd->pool, p);
if (!p)
return XML_STATUS_ERROR;
- curBase = p;
+ parser->m_curBase = p;
}
else
- curBase = NULL;
+ parser->m_curBase = NULL;
return XML_STATUS_OK;
}
@@ -1575,7 +1496,7 @@ XML_GetBase(XML_Parser parser)
{
if (parser == NULL)
return NULL;
- return curBase;
+ return parser->m_curBase;
}
int XMLCALL
@@ -1583,7 +1504,7 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser)
{
if (parser == NULL)
return -1;
- return nSpecifiedAtts;
+ return parser->m_nSpecifiedAtts;
}
int XMLCALL
@@ -1591,7 +1512,7 @@ XML_GetIdAttributeIndex(XML_Parser parser)
{
if (parser == NULL)
return -1;
- return idAttIndex;
+ return parser->m_idAttIndex;
}
#ifdef XML_ATTR_INFO
@@ -1600,7 +1521,7 @@ XML_GetAttributeInfo(XML_Parser parser)
{
if (parser == NULL)
return NULL;
- return attInfo;
+ return parser->m_attInfo;
}
#endif
@@ -1611,22 +1532,22 @@ XML_SetElementHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- startElementHandler = start;
- endElementHandler = end;
+ parser->m_startElementHandler = start;
+ parser->m_endElementHandler = end;
}
void XMLCALL
XML_SetStartElementHandler(XML_Parser parser,
XML_StartElementHandler start) {
if (parser != NULL)
- startElementHandler = start;
+ parser->m_startElementHandler = start;
}
void XMLCALL
XML_SetEndElementHandler(XML_Parser parser,
XML_EndElementHandler end) {
if (parser != NULL)
- endElementHandler = end;
+ parser->m_endElementHandler = end;
}
void XMLCALL
@@ -1634,7 +1555,7 @@ XML_SetCharacterDataHandler(XML_Parser parser,
XML_CharacterDataHandler handler)
{
if (parser != NULL)
- characterDataHandler = handler;
+ parser->m_characterDataHandler = handler;
}
void XMLCALL
@@ -1642,7 +1563,7 @@ XML_SetProcessingInstructionHandler(XML_Parser parser,
XML_ProcessingInstructionHandler handler)
{
if (parser != NULL)
- processingInstructionHandler = handler;
+ parser->m_processingInstructionHandler = handler;
}
void XMLCALL
@@ -1650,7 +1571,7 @@ XML_SetCommentHandler(XML_Parser parser,
XML_CommentHandler handler)
{
if (parser != NULL)
- commentHandler = handler;
+ parser->m_commentHandler = handler;
}
void XMLCALL
@@ -1660,22 +1581,22 @@ XML_SetCdataSectionHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- startCdataSectionHandler = start;
- endCdataSectionHandler = end;
+ parser->m_startCdataSectionHandler = start;
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
XML_SetStartCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start) {
if (parser != NULL)
- startCdataSectionHandler = start;
+ parser->m_startCdataSectionHandler = start;
}
void XMLCALL
XML_SetEndCdataSectionHandler(XML_Parser parser,
XML_EndCdataSectionHandler end) {
if (parser != NULL)
- endCdataSectionHandler = end;
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
@@ -1684,8 +1605,8 @@ XML_SetDefaultHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_FALSE;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_FALSE;
}
void XMLCALL
@@ -1694,8 +1615,8 @@ XML_SetDefaultHandlerExpand(XML_Parser parser,
{
if (parser == NULL)
return;
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_TRUE;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
}
void XMLCALL
@@ -1705,22 +1626,22 @@ XML_SetDoctypeDeclHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- startDoctypeDeclHandler = start;
- endDoctypeDeclHandler = end;
+ parser->m_startDoctypeDeclHandler = start;
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
XML_SetStartDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start) {
if (parser != NULL)
- startDoctypeDeclHandler = start;
+ parser->m_startDoctypeDeclHandler = start;
}
void XMLCALL
XML_SetEndDoctypeDeclHandler(XML_Parser parser,
XML_EndDoctypeDeclHandler end) {
if (parser != NULL)
- endDoctypeDeclHandler = end;
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
@@ -1728,7 +1649,7 @@ XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
XML_UnparsedEntityDeclHandler handler)
{
if (parser != NULL)
- unparsedEntityDeclHandler = handler;
+ parser->m_unparsedEntityDeclHandler = handler;
}
void XMLCALL
@@ -1736,7 +1657,7 @@ XML_SetNotationDeclHandler(XML_Parser parser,
XML_NotationDeclHandler handler)
{
if (parser != NULL)
- notationDeclHandler = handler;
+ parser->m_notationDeclHandler = handler;
}
void XMLCALL
@@ -1746,22 +1667,22 @@ XML_SetNamespaceDeclHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- startNamespaceDeclHandler = start;
- endNamespaceDeclHandler = end;
+ parser->m_startNamespaceDeclHandler = start;
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
XML_SetStartNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start) {
if (parser != NULL)
- startNamespaceDeclHandler = start;
+ parser->m_startNamespaceDeclHandler = start;
}
void XMLCALL
XML_SetEndNamespaceDeclHandler(XML_Parser parser,
XML_EndNamespaceDeclHandler end) {
if (parser != NULL)
- endNamespaceDeclHandler = end;
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
@@ -1769,7 +1690,7 @@ XML_SetNotStandaloneHandler(XML_Parser parser,
XML_NotStandaloneHandler handler)
{
if (parser != NULL)
- notStandaloneHandler = handler;
+ parser->m_notStandaloneHandler = handler;
}
void XMLCALL
@@ -1777,7 +1698,7 @@ XML_SetExternalEntityRefHandler(XML_Parser parser,
XML_ExternalEntityRefHandler handler)
{
if (parser != NULL)
- externalEntityRefHandler = handler;
+ parser->m_externalEntityRefHandler = handler;
}
void XMLCALL
@@ -1786,9 +1707,9 @@ XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
if (parser == NULL)
return;
if (arg)
- externalEntityRefHandlerArg = (XML_Parser)arg;
+ parser->m_externalEntityRefHandlerArg = (XML_Parser)arg;
else
- externalEntityRefHandlerArg = parser;
+ parser->m_externalEntityRefHandlerArg = parser;
}
void XMLCALL
@@ -1796,7 +1717,7 @@ XML_SetSkippedEntityHandler(XML_Parser parser,
XML_SkippedEntityHandler handler)
{
if (parser != NULL)
- skippedEntityHandler = handler;
+ parser->m_skippedEntityHandler = handler;
}
void XMLCALL
@@ -1806,8 +1727,8 @@ XML_SetUnknownEncodingHandler(XML_Parser parser,
{
if (parser == NULL)
return;
- unknownEncodingHandler = handler;
- unknownEncodingHandlerData = data;
+ parser->m_unknownEncodingHandler = handler;
+ parser->m_unknownEncodingHandlerData = data;
}
void XMLCALL
@@ -1815,7 +1736,7 @@ XML_SetElementDeclHandler(XML_Parser parser,
XML_ElementDeclHandler eldecl)
{
if (parser != NULL)
- elementDeclHandler = eldecl;
+ parser->m_elementDeclHandler = eldecl;
}
void XMLCALL
@@ -1823,7 +1744,7 @@ XML_SetAttlistDeclHandler(XML_Parser parser,
XML_AttlistDeclHandler attdecl)
{
if (parser != NULL)
- attlistDeclHandler = attdecl;
+ parser->m_attlistDeclHandler = attdecl;
}
void XMLCALL
@@ -1831,14 +1752,14 @@ XML_SetEntityDeclHandler(XML_Parser parser,
XML_EntityDeclHandler handler)
{
if (parser != NULL)
- entityDeclHandler = handler;
+ parser->m_entityDeclHandler = handler;
}
void XMLCALL
XML_SetXmlDeclHandler(XML_Parser parser,
XML_XmlDeclHandler handler) {
if (parser != NULL)
- xmlDeclHandler = handler;
+ parser->m_xmlDeclHandler = handler;
}
int XMLCALL
@@ -1848,10 +1769,10 @@ XML_SetParamEntityParsing(XML_Parser parser,
if (parser == NULL)
return 0;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
#ifdef XML_DTD
- paramEntityParsing = peParsing;
+ parser->m_paramEntityParsing = peParsing;
return 1;
#else
return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
@@ -1867,9 +1788,9 @@ XML_SetHashSalt(XML_Parser parser,
if (parser->m_parentParser)
return XML_SetHashSalt(parser->m_parentParser, hash_salt);
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
- hash_secret_salt = hash_salt;
+ parser->m_hash_secret_salt = hash_salt;
return 1;
}
@@ -1881,37 +1802,38 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
return XML_STATUS_ERROR;
}
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && !startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
if (len == 0) {
- ps_finalBuffer = (XML_Bool)isFinal;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
if (!isFinal)
return XML_STATUS_OK;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
/* If data are left over from last buffer, and we now know that these
data are the final chunk of input, then we have to check them again
to detect errors based on that fact.
*/
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode == XML_ERROR_NONE) {
- switch (ps_parsing) {
+ if (parser->m_errorCode == XML_ERROR_NONE) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
/* It is hard to be certain, but it seems that this case
* cannot occur. This code is cleaning up a previous parse
@@ -1925,54 +1847,54 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
*
* LCOV_EXCL_START
*/
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return XML_STATUS_SUSPENDED;
/* LCOV_EXCL_STOP */
case XML_INITIALIZED:
case XML_PARSING:
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
/* fall through */
default:
return XML_STATUS_OK;
}
}
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
#ifndef XML_CONTEXT_BYTES
- else if (bufferPtr == bufferEnd) {
+ else if (parser->m_bufferPtr == parser->m_bufferEnd) {
const char *end;
int nLeftOver;
enum XML_Status result;
/* Detect overflow (a+b > MAX <==> b > MAX-a) */
- if (len > ((XML_Size)-1) / 2 - parseEndByteIndex) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = NULL;
- processor = errorProcessor;
+ if (len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
- parseEndByteIndex += len;
- positionPtr = s;
- ps_finalBuffer = (XML_Bool)isFinal;
+ parser->m_parseEndByteIndex += len;
+ parser->m_positionPtr = s;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+ parser->m_errorCode = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return XML_STATUS_OK;
}
/* fall through */
@@ -1981,35 +1903,33 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
}
}
- XmlUpdatePosition(encoding, positionPtr, end, &position);
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end, &parser->m_position);
nLeftOver = s + len - end;
if (nLeftOver) {
- if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+ if (parser->m_buffer == NULL || nLeftOver > parser->m_bufferLim - parser->m_buffer) {
/* avoid _signed_ integer overflow */
char *temp = NULL;
const int bytesToAllocate = (int)((unsigned)len * 2U);
if (bytesToAllocate > 0) {
- temp = (buffer == NULL
- ? (char *)MALLOC(bytesToAllocate)
- : (char *)REALLOC(buffer, bytesToAllocate));
+ temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
}
if (temp == NULL) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = NULL;
- processor = errorProcessor;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
- buffer = temp;
- bufferLim = buffer + bytesToAllocate;
+ parser->m_buffer = temp;
+ parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
}
- memcpy(buffer, end, nLeftOver);
+ memcpy(parser->m_buffer, end, nLeftOver);
}
- bufferPtr = buffer;
- bufferEnd = buffer + nLeftOver;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
- eventPtr = bufferPtr;
- eventEndPtr = bufferPtr;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer + nLeftOver;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_eventPtr = parser->m_bufferPtr;
+ parser->m_eventEndPtr = parser->m_bufferPtr;
return result;
}
#endif /* not defined XML_CONTEXT_BYTES */
@@ -2032,53 +1952,54 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
if (parser == NULL)
return XML_STATUS_ERROR;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && !startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
- start = bufferPtr;
- positionPtr = start;
- bufferEnd += len;
- parseEndPtr = bufferEnd;
- parseEndByteIndex += len;
- ps_finalBuffer = (XML_Bool)isFinal;
+ start = parser->m_bufferPtr;
+ parser->m_positionPtr = start;
+ parser->m_bufferEnd += len;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_parseEndByteIndex += len;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
default: ; /* should not happen */
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
@@ -2088,52 +2009,59 @@ XML_GetBuffer(XML_Parser parser, int len)
if (parser == NULL)
return NULL;
if (len < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return NULL;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return NULL;
default: ;
}
- if (len > bufferLim - bufferEnd) {
+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
#ifdef XML_CONTEXT_BYTES
int keep;
#endif /* defined XML_CONTEXT_BYTES */
/* Do not invoke signed arithmetic overflow: */
- int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
+ int neededSize = (int) ((unsigned)len +
+ (unsigned)EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd,
+ parser->m_bufferPtr));
if (neededSize < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
#ifdef XML_CONTEXT_BYTES
- keep = (int)(bufferPtr - buffer);
+ keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
neededSize += keep;
#endif /* defined XML_CONTEXT_BYTES */
- if (neededSize <= bufferLim - buffer) {
+ if (neededSize <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
#ifdef XML_CONTEXT_BYTES
- if (keep < bufferPtr - buffer) {
- int offset = (int)(bufferPtr - buffer) - keep;
- memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
- bufferEnd -= offset;
- bufferPtr -= offset;
+ if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
+ int offset = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer) - keep;
+ /* The buffer pointers cannot be NULL here; we have at least some bytes in the buffer */
+ memmove(parser->m_buffer, &parser->m_buffer[offset], parser->m_bufferEnd - parser->m_bufferPtr + keep);
+ parser->m_bufferEnd -= offset;
+ parser->m_bufferPtr -= offset;
}
#else
- memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
- bufferEnd = buffer + (bufferEnd - bufferPtr);
- bufferPtr = buffer;
+ if (parser->m_buffer && parser->m_bufferPtr) {
+ memmove(parser->m_buffer, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ parser->m_bufferEnd = parser->m_buffer +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ parser->m_bufferPtr = parser->m_buffer;
+ }
#endif /* not defined XML_CONTEXT_BYTES */
}
else {
char *newBuf;
- int bufferSize = (int)(bufferLim - bufferPtr);
+ int bufferSize = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
if (bufferSize == 0)
bufferSize = INIT_BUFFER_SIZE;
do {
@@ -2141,43 +2069,52 @@ XML_GetBuffer(XML_Parser parser, int len)
bufferSize = (int) (2U * (unsigned) bufferSize);
} while (bufferSize < neededSize && bufferSize > 0);
if (bufferSize <= 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- newBuf = (char *)MALLOC(bufferSize);
+ newBuf = (char *)MALLOC(parser, bufferSize);
if (newBuf == 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- bufferLim = newBuf + bufferSize;
+ parser->m_bufferLim = newBuf + bufferSize;
#ifdef XML_CONTEXT_BYTES
- if (bufferPtr) {
- int keep = (int)(bufferPtr - buffer);
+ if (parser->m_bufferPtr) {
+ int keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
- memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
- FREE(buffer);
- buffer = newBuf;
- bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
- bufferPtr = buffer + keep;
+ memcpy(newBuf, &parser->m_bufferPtr[-keep],
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + keep);
+ FREE(parser, parser->m_buffer);
+ parser->m_buffer = newBuf;
+ parser->m_bufferEnd = parser->m_buffer +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + keep;
+ parser->m_bufferPtr = parser->m_buffer + keep;
}
else {
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
}
#else
- if (bufferPtr) {
- memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
- FREE(buffer);
+ if (parser->m_bufferPtr) {
+ memcpy(newBuf, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ FREE(parser, parser->m_buffer);
+ parser->m_bufferEnd = newBuf +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ }
+ else {
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
}
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
#endif /* not defined XML_CONTEXT_BYTES */
}
- eventPtr = eventEndPtr = NULL;
- positionPtr = NULL;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
}
- return bufferEnd;
+ return parser->m_bufferEnd;
}
enum XML_Status XMLCALL
@@ -2185,29 +2122,29 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable)
{
if (parser == NULL)
return XML_STATUS_ERROR;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
if (resumable) {
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
break;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
default:
if (resumable) {
#ifdef XML_DTD
- if (isParamEntity) {
- errorCode = XML_ERROR_SUSPEND_PE;
+ if (parser->m_isParamEntity) {
+ parser->m_errorCode = XML_ERROR_SUSPEND_PE;
return XML_STATUS_ERROR;
}
#endif
- ps_parsing = XML_SUSPENDED;
+ parser->m_parsingStatus.parsing = XML_SUSPENDED;
}
else
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
}
return XML_STATUS_OK;
}
@@ -2219,36 +2156,36 @@ XML_ResumeParser(XML_Parser parser)
if (parser == NULL)
return XML_STATUS_ERROR;
- if (ps_parsing != XML_SUSPENDED) {
- errorCode = XML_ERROR_NOT_SUSPENDED;
+ if (parser->m_parsingStatus.parsing != XML_SUSPENDED) {
+ parser->m_errorCode = XML_ERROR_NOT_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
- if (ps_finalBuffer) {
- ps_parsing = XML_FINISHED;
+ if (parser->m_parsingStatus.finalBuffer) {
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
default: ;
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
@@ -2266,7 +2203,7 @@ XML_GetErrorCode(XML_Parser parser)
{
if (parser == NULL)
return XML_ERROR_INVALID_ARGUMENT;
- return errorCode;
+ return parser->m_errorCode;
}
XML_Index XMLCALL
@@ -2274,8 +2211,8 @@ XML_GetCurrentByteIndex(XML_Parser parser)
{
if (parser == NULL)
return -1;
- if (eventPtr)
- return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
+ if (parser->m_eventPtr)
+ return (XML_Index)(parser->m_parseEndByteIndex - (parser->m_parseEndPtr - parser->m_eventPtr));
return -1;
}
@@ -2284,8 +2221,8 @@ XML_GetCurrentByteCount(XML_Parser parser)
{
if (parser == NULL)
return 0;
- if (eventEndPtr && eventPtr)
- return (int)(eventEndPtr - eventPtr);
+ if (parser->m_eventEndPtr && parser->m_eventPtr)
+ return (int)(parser->m_eventEndPtr - parser->m_eventPtr);
return 0;
}
@@ -2295,12 +2232,12 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size)
#ifdef XML_CONTEXT_BYTES
if (parser == NULL)
return NULL;
- if (eventPtr && buffer) {
+ if (parser->m_eventPtr && parser->m_buffer) {
if (offset != NULL)
- *offset = (int)(eventPtr - buffer);
+ *offset = (int)(parser->m_eventPtr - parser->m_buffer);
if (size != NULL)
- *size = (int)(bufferEnd - buffer);
- return buffer;
+ *size = (int)(parser->m_bufferEnd - parser->m_buffer);
+ return parser->m_buffer;
}
#else
(void)parser;
@@ -2315,11 +2252,11 @@ XML_GetCurrentLineNumber(XML_Parser parser)
{
if (parser == NULL)
return 0;
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.lineNumber + 1;
+ return parser->m_position.lineNumber + 1;
}
XML_Size XMLCALL
@@ -2327,18 +2264,18 @@ XML_GetCurrentColumnNumber(XML_Parser parser)
{
if (parser == NULL)
return 0;
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.columnNumber;
+ return parser->m_position.columnNumber;
}
void XMLCALL
XML_FreeContentModel(XML_Parser parser, XML_Content *model)
{
if (parser != NULL)
- FREE(model);
+ FREE(parser, model);
}
void * XMLCALL
@@ -2346,7 +2283,7 @@ XML_MemMalloc(XML_Parser parser, size_t size)
{
if (parser == NULL)
return NULL;
- return MALLOC(size);
+ return MALLOC(parser, size);
}
void * XMLCALL
@@ -2354,14 +2291,14 @@ XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
{
if (parser == NULL)
return NULL;
- return REALLOC(ptr, size);
+ return REALLOC(parser, ptr, size);
}
void XMLCALL
XML_MemFree(XML_Parser parser, void *ptr)
{
if (parser != NULL)
- FREE(ptr);
+ FREE(parser, ptr);
}
void XMLCALL
@@ -2369,65 +2306,110 @@ XML_DefaultCurrent(XML_Parser parser)
{
if (parser == NULL)
return;
- if (defaultHandler) {
- if (openInternalEntities)
+ if (parser->m_defaultHandler) {
+ if (parser->m_openInternalEntities)
reportDefault(parser,
- internalEncoding,
- openInternalEntities->internalEventPtr,
- openInternalEntities->internalEventEndPtr);
+ parser->m_internalEncoding,
+ parser->m_openInternalEntities->internalEventPtr,
+ parser->m_openInternalEntities->internalEventEndPtr);
else
- reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ reportDefault(parser, parser->m_encoding, parser->m_eventPtr, parser->m_eventEndPtr);
}
}
const XML_LChar * XMLCALL
XML_ErrorString(enum XML_Error code)
{
- static const XML_LChar* const message[] = {
- 0,
- XML_L("out of memory"),
- XML_L("syntax error"),
- XML_L("no element found"),
- XML_L("not well-formed (invalid token)"),
- XML_L("unclosed token"),
- XML_L("partial character"),
- XML_L("mismatched tag"),
- XML_L("duplicate attribute"),
- XML_L("junk after document element"),
- XML_L("illegal parameter entity reference"),
- XML_L("undefined entity"),
- XML_L("recursive entity reference"),
- XML_L("asynchronous entity"),
- XML_L("reference to invalid character number"),
- XML_L("reference to binary entity"),
- XML_L("reference to external entity in attribute"),
- XML_L("XML or text declaration not at start of entity"),
- XML_L("unknown encoding"),
- XML_L("encoding specified in XML declaration is incorrect"),
- XML_L("unclosed CDATA section"),
- XML_L("error in processing external entity reference"),
- XML_L("document is not standalone"),
- XML_L("unexpected parser state - please send a bug report"),
- XML_L("entity declared in parameter entity"),
- XML_L("requested feature requires XML_DTD support in Expat"),
- XML_L("cannot change setting once parsing has begun"),
- XML_L("unbound prefix"),
- XML_L("must not undeclare prefix"),
- XML_L("incomplete markup in parameter entity"),
- XML_L("XML declaration not well-formed"),
- XML_L("text declaration not well-formed"),
- XML_L("illegal character(s) in public id"),
- XML_L("parser suspended"),
- XML_L("parser not suspended"),
- XML_L("parsing aborted"),
- XML_L("parsing finished"),
- XML_L("cannot suspend in external parameter entity"),
- XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
- XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
- XML_L("prefix must not be bound to one of the reserved namespace names")
- };
- if (code > 0 && code < sizeof(message)/sizeof(message[0]))
- return message[code];
+ switch (code) {
+ case XML_ERROR_NONE:
+ return NULL;
+ case XML_ERROR_NO_MEMORY:
+ return XML_L("out of memory");
+ case XML_ERROR_SYNTAX:
+ return XML_L("syntax error");
+ case XML_ERROR_NO_ELEMENTS:
+ return XML_L("no element found");
+ case XML_ERROR_INVALID_TOKEN:
+ return XML_L("not well-formed (invalid token)");
+ case XML_ERROR_UNCLOSED_TOKEN:
+ return XML_L("unclosed token");
+ case XML_ERROR_PARTIAL_CHAR:
+ return XML_L("partial character");
+ case XML_ERROR_TAG_MISMATCH:
+ return XML_L("mismatched tag");
+ case XML_ERROR_DUPLICATE_ATTRIBUTE:
+ return XML_L("duplicate attribute");
+ case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
+ return XML_L("junk after document element");
+ case XML_ERROR_PARAM_ENTITY_REF:
+ return XML_L("illegal parameter entity reference");
+ case XML_ERROR_UNDEFINED_ENTITY:
+ return XML_L("undefined entity");
+ case XML_ERROR_RECURSIVE_ENTITY_REF:
+ return XML_L("recursive entity reference");
+ case XML_ERROR_ASYNC_ENTITY:
+ return XML_L("asynchronous entity");
+ case XML_ERROR_BAD_CHAR_REF:
+ return XML_L("reference to invalid character number");
+ case XML_ERROR_BINARY_ENTITY_REF:
+ return XML_L("reference to binary entity");
+ case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
+ return XML_L("reference to external entity in attribute");
+ case XML_ERROR_MISPLACED_XML_PI:
+ return XML_L("XML or text declaration not at start of entity");
+ case XML_ERROR_UNKNOWN_ENCODING:
+ return XML_L("unknown encoding");
+ case XML_ERROR_INCORRECT_ENCODING:
+ return XML_L("encoding specified in XML declaration is incorrect");
+ case XML_ERROR_UNCLOSED_CDATA_SECTION:
+ return XML_L("unclosed CDATA section");
+ case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
+ return XML_L("error in processing external entity reference");
+ case XML_ERROR_NOT_STANDALONE:
+ return XML_L("document is not standalone");
+ case XML_ERROR_UNEXPECTED_STATE:
+ return XML_L("unexpected parser state - please send a bug report");
+ case XML_ERROR_ENTITY_DECLARED_IN_PE:
+ return XML_L("entity declared in parameter entity");
+ case XML_ERROR_FEATURE_REQUIRES_XML_DTD:
+ return XML_L("requested feature requires XML_DTD support in Expat");
+ case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING:
+ return XML_L("cannot change setting once parsing has begun");
+ /* Added in 1.95.7. */
+ case XML_ERROR_UNBOUND_PREFIX:
+ return XML_L("unbound prefix");
+ /* Added in 1.95.8. */
+ case XML_ERROR_UNDECLARING_PREFIX:
+ return XML_L("must not undeclare prefix");
+ case XML_ERROR_INCOMPLETE_PE:
+ return XML_L("incomplete markup in parameter entity");
+ case XML_ERROR_XML_DECL:
+ return XML_L("XML declaration not well-formed");
+ case XML_ERROR_TEXT_DECL:
+ return XML_L("text declaration not well-formed");
+ case XML_ERROR_PUBLICID:
+ return XML_L("illegal character(s) in public id");
+ case XML_ERROR_SUSPENDED:
+ return XML_L("parser suspended");
+ case XML_ERROR_NOT_SUSPENDED:
+ return XML_L("parser not suspended");
+ case XML_ERROR_ABORTED:
+ return XML_L("parsing aborted");
+ case XML_ERROR_FINISHED:
+ return XML_L("parsing finished");
+ case XML_ERROR_SUSPEND_PE:
+ return XML_L("cannot suspend in external parameter entity");
+ /* Added in 2.0.0. */
+ case XML_ERROR_RESERVED_PREFIX_XML:
+ return XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name");
+ case XML_ERROR_RESERVED_PREFIX_XMLNS:
+ return XML_L("reserved prefix (xmlns) must not be declared or undeclared");
+ case XML_ERROR_RESERVED_NAMESPACE_URI:
+ return XML_L("prefix must not be bound to one of the reserved namespace names");
+ /* Added in 2.2.5. */
+ case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
+ return XML_L("invalid argument");
+ }
return NULL;
}
@@ -2510,12 +2492,12 @@ XML_GetFeatureList(void)
static XML_Bool
storeRawNames(XML_Parser parser)
{
- TAG *tag = tagStack;
+ TAG *tag = parser->m_tagStack;
while (tag) {
int bufSize;
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
char *rawNameBuf = tag->buf + nameLen;
- /* Stop if already stored. Since tagStack is a stack, we can stop
+ /* Stop if already stored. Since m_tagStack is a stack, we can stop
at the first entry that has already been copied; everything
below it in the stack is already been accounted for in a
previous call to this function.
@@ -2527,7 +2509,7 @@ storeRawNames(XML_Parser parser)
*/
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
if (bufSize > tag->bufEnd - tag->buf) {
- char *temp = (char *)REALLOC(tag->buf, bufSize);
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
return XML_FALSE;
/* if tag->name.str points to tag->buf (only when namespace
@@ -2558,8 +2540,8 @@ contentProcessor(XML_Parser parser,
const char *end,
const char **endPtr)
{
- enum XML_Error result = doContent(parser, 0, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doContent(parser, 0, parser->m_encoding, start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
if (!storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
@@ -2576,7 +2558,7 @@ externalEntityInitProcessor(XML_Parser parser,
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = externalEntityInitProcessor2;
+ parser->m_processor = externalEntityInitProcessor2;
return externalEntityInitProcessor2(parser, start, end, endPtr);
}
@@ -2587,7 +2569,7 @@ externalEntityInitProcessor2(XML_Parser parser,
const char **endPtr)
{
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- int tok = XmlContentTok(encoding, start, end, &next);
+ int tok = XmlContentTok(parser->m_encoding, start, end, &next);
switch (tok) {
case XML_TOK_BOM:
/* If we are at the end of the buffer, this would cause the next stage,
@@ -2595,28 +2577,28 @@ externalEntityInitProcessor2(XML_Parser parser,
doContent (by detecting XML_TOK_NONE) without processing any xml text
declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
*/
- if (next == end && !ps_finalBuffer) {
+ if (next == end && !parser->m_parsingStatus.finalBuffer) {
*endPtr = next;
return XML_ERROR_NONE;
}
start = next;
break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityInitProcessor3;
+ parser->m_processor = externalEntityInitProcessor3;
return externalEntityInitProcessor3(parser, start, end, endPtr);
}
@@ -2628,9 +2610,9 @@ externalEntityInitProcessor3(XML_Parser parser,
{
int tok;
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- eventPtr = start;
- tok = XmlContentTok(encoding, start, end, &next);
- eventEndPtr = next;
+ parser->m_eventPtr = start;
+ tok = XmlContentTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
case XML_TOK_XML_DECL:
@@ -2639,7 +2621,7 @@ externalEntityInitProcessor3(XML_Parser parser,
result = processXmlDecl(parser, 1, start, next);
if (result != XML_ERROR_NONE)
return result;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*endPtr = next;
return XML_ERROR_NONE;
@@ -2651,20 +2633,20 @@ externalEntityInitProcessor3(XML_Parser parser,
}
break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityContentProcessor;
- tagLevel = 1;
+ parser->m_processor = externalEntityContentProcessor;
+ parser->m_tagLevel = 1;
return externalEntityContentProcessor(parser, start, end, endPtr);
}
@@ -2674,8 +2656,8 @@ externalEntityContentProcessor(XML_Parser parser,
const char *end,
const char **endPtr)
{
- enum XML_Error result = doContent(parser, 1, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doContent(parser, 1, parser->m_encoding, start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
if (!storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
@@ -2693,17 +2675,17 @@ doContent(XML_Parser parser,
XML_Bool haveMore)
{
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD * const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
@@ -2718,18 +2700,18 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
}
*eventEndPP = end;
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
*/
if (startTagLevel == 0)
return XML_ERROR_NO_ELEMENTS;
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = end;
return XML_ERROR_NONE;
@@ -2739,7 +2721,7 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
}
if (startTagLevel > 0) {
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = s;
return XML_ERROR_NONE;
@@ -2768,9 +2750,9 @@ doContent(XML_Parser parser,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (ch) {
- if (characterDataHandler)
- characterDataHandler(handlerArg, &ch, 1);
- else if (defaultHandler)
+ if (parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -2792,9 +2774,9 @@ doContent(XML_Parser parser,
return XML_ERROR_ENTITY_DECLARED_IN_PE;
}
else if (!entity) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
- else if (defaultHandler)
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -2804,10 +2786,10 @@ doContent(XML_Parser parser,
return XML_ERROR_BINARY_ENTITY_REF;
if (entity->textPtr) {
enum XML_Error result;
- if (!defaultExpandInternalEntities) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, entity->name, 0);
- else if (defaultHandler)
+ if (!parser->m_defaultExpandInternalEntities) {
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name, 0);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -2815,22 +2797,22 @@ doContent(XML_Parser parser,
if (result != XML_ERROR_NONE)
return result;
}
- else if (externalEntityRefHandler) {
+ else if (parser->m_externalEntityRefHandler) {
const XML_Char *context;
entity->open = XML_TRUE;
context = getContext(parser);
entity->open = XML_FALSE;
if (!context)
return XML_ERROR_NO_MEMORY;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
context,
entity->base,
entity->systemId,
entity->publicId))
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -2841,29 +2823,29 @@ doContent(XML_Parser parser,
TAG *tag;
enum XML_Error result;
XML_Char *toPtr;
- if (freeTagList) {
- tag = freeTagList;
- freeTagList = freeTagList->parent;
+ if (parser->m_freeTagList) {
+ tag = parser->m_freeTagList;
+ parser->m_freeTagList = parser->m_freeTagList->parent;
}
else {
- tag = (TAG *)MALLOC(sizeof(TAG));
+ tag = (TAG *)MALLOC(parser, sizeof(TAG));
if (!tag)
return XML_ERROR_NO_MEMORY;
- tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+ tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE);
if (!tag->buf) {
- FREE(tag);
+ FREE(parser, tag);
return XML_ERROR_NO_MEMORY;
}
tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
}
tag->bindings = NULL;
- tag->parent = tagStack;
- tagStack = tag;
+ tag->parent = parser->m_tagStack;
+ parser->m_tagStack = tag;
tag->name.localPart = NULL;
tag->name.prefix = NULL;
tag->rawName = s + enc->minBytesPerChar;
tag->rawNameLength = XmlNameLength(enc, tag->rawName);
- ++tagLevel;
+ ++parser->m_tagLevel;
{
const char *rawNameEnd = tag->rawName + tag->rawNameLength;
const char *fromPtr = tag->rawName;
@@ -2881,7 +2863,7 @@ doContent(XML_Parser parser,
}
bufSize = (int)(tag->bufEnd - tag->buf) << 1;
{
- char *temp = (char *)REALLOC(tag->buf, bufSize);
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
tag->buf = temp;
@@ -2895,12 +2877,12 @@ doContent(XML_Parser parser,
result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
if (result)
return result;
- if (startElementHandler)
- startElementHandler(handlerArg, tag->name.str,
- (const XML_Char **)atts);
- else if (defaultHandler)
+ if (parser->m_startElementHandler)
+ parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
+ (const XML_Char **)parser->m_atts);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
}
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
@@ -2912,45 +2894,49 @@ doContent(XML_Parser parser,
BINDING *bindings = NULL;
XML_Bool noElmHandlers = XML_TRUE;
TAG_NAME name;
- name.str = poolStoreString(&tempPool, enc, rawName,
+ name.str = poolStoreString(&parser->m_tempPool, enc, rawName,
rawName + XmlNameLength(enc, rawName));
if (!name.str)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
result = storeAtts(parser, enc, s, &name, &bindings);
if (result != XML_ERROR_NONE) {
freeBindings(parser, bindings);
return result;
}
- poolFinish(&tempPool);
- if (startElementHandler) {
- startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ poolFinish(&parser->m_tempPool);
+ if (parser->m_startElementHandler) {
+ parser->m_startElementHandler(parser->m_handlerArg, name.str, (const XML_Char **)parser->m_atts);
noElmHandlers = XML_FALSE;
}
- if (endElementHandler) {
- if (startElementHandler)
+ if (parser->m_endElementHandler) {
+ if (parser->m_startElementHandler)
*eventPP = *eventEndPP;
- endElementHandler(handlerArg, name.str);
+ parser->m_endElementHandler(parser->m_handlerArg, name.str);
noElmHandlers = XML_FALSE;
}
- if (noElmHandlers && defaultHandler)
+ if (noElmHandlers && parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
freeBindings(parser, bindings);
}
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
+ if ((parser->m_tagLevel == 0) && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ parser->m_processor = epilogProcessor;
+ else
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
break;
case XML_TOK_END_TAG:
- if (tagLevel == startTagLevel)
+ if (parser->m_tagLevel == startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
else {
int len;
const char *rawName;
- TAG *tag = tagStack;
- tagStack = tag->parent;
- tag->parent = freeTagList;
- freeTagList = tag;
+ TAG *tag = parser->m_tagStack;
+ parser->m_tagStack = tag->parent;
+ tag->parent = parser->m_freeTagList;
+ parser->m_freeTagList = tag;
rawName = s + enc->minBytesPerChar*2;
len = XmlNameLength(enc, rawName);
if (len != tag->rawNameLength
@@ -2958,13 +2944,13 @@ doContent(XML_Parser parser,
*eventPP = rawName;
return XML_ERROR_TAG_MISMATCH;
}
- --tagLevel;
- if (endElementHandler) {
+ --parser->m_tagLevel;
+ if (parser->m_endElementHandler) {
const XML_Char *localPart;
const XML_Char *prefix;
XML_Char *uri;
localPart = tag->name.localPart;
- if (ns && localPart) {
+ if (parser->m_ns && localPart) {
/* localPart and prefix may have been overwritten in
tag->name.str, since this points to the binding->uri
buffer which gets re-used; so we have to add them again
@@ -2973,26 +2959,26 @@ doContent(XML_Parser parser,
/* don't need to check for space - already done in storeAtts() */
while (*localPart) *uri++ = *localPart++;
prefix = (XML_Char *)tag->name.prefix;
- if (ns_triplets && prefix) {
- *uri++ = namespaceSeparator;
+ if (parser->m_ns_triplets && prefix) {
+ *uri++ = parser->m_namespaceSeparator;
while (*prefix) *uri++ = *prefix++;
}
*uri = XML_T('\0');
}
- endElementHandler(handlerArg, tag->name.str);
+ parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
while (tag->bindings) {
BINDING *b = tag->bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
tag->bindings = tag->bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
b->prefix->binding = b->prevPrefixBinding;
}
- if (tagLevel == 0)
+ if (parser->m_tagLevel == 0)
return epilogProcessor(parser, next, end, nextPtr);
}
break;
@@ -3001,30 +2987,30 @@ doContent(XML_Parser parser,
int n = XmlCharRefNumber(enc, s);
if (n < 0)
return XML_ERROR_BAD_CHAR_REF;
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char buf[XML_ENCODE_MAX];
- characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ parser->m_characterDataHandler(parser->m_handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
case XML_TOK_XML_DECL:
return XML_ERROR_MISPLACED_XML_PI;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_CDATA_SECT_OPEN:
{
enum XML_Error result;
- if (startCdataSectionHandler)
- startCdataSectionHandler(handlerArg);
-#if 0
+ if (parser->m_startCdataSectionHandler)
+ parser->m_startCdataSectionHandler(parser->m_handlerArg);
+/* BEGIN disabled code */
/* Suppose you doing a transformation on a document that involves
changing only the character data. You set up a defaultHandler
and a characterDataHandler. The defaultHandler simply copies
@@ -3037,16 +3023,16 @@ doContent(XML_Parser parser,
However, now we have a start/endCdataSectionHandler, so it seems
easier to let the user deal with this.
*/
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
+ else if (0 && parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0);
+/* END disabled code */
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
if (result != XML_ERROR_NONE)
return result;
else if (!next) {
- processor = cdataSectionProcessor;
+ parser->m_processor = cdataSectionProcessor;
return result;
}
}
@@ -3056,19 +3042,19 @@ doContent(XML_Parser parser,
*nextPtr = s;
return XML_ERROR_NONE;
}
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
if (MUST_CONVERT(enc, s)) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
- characterDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
}
else
- characterDataHandler(handlerArg,
+ parser->m_characterDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)end - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
@@ -3077,7 +3063,7 @@ doContent(XML_Parser parser,
*eventPP = end;
return XML_ERROR_NO_ELEMENTS;
}
- if (tagLevel != startTagLevel) {
+ if (parser->m_tagLevel != startTagLevel) {
*eventPP = end;
return XML_ERROR_ASYNC_ENTITY;
}
@@ -3085,26 +3071,26 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
case XML_TOK_DATA_CHARS:
{
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
if (charDataHandler) {
if (MUST_CONVERT(enc, s)) {
for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
}
else
- charDataHandler(handlerArg,
+ charDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)next - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
@@ -3124,13 +3110,13 @@ doContent(XML_Parser parser,
*
* LCOV_EXCL_START
*/
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
/* LCOV_EXCL_STOP */
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
@@ -3143,7 +3129,7 @@ doContent(XML_Parser parser,
}
/* This function does not call free() on the allocated memory, merely
- * moving it to the parser's freeBindingList where it can be freed or
+ * moving it to the parser's m_freeBindingList where it can be freed or
* reused as appropriate.
*/
static void
@@ -3152,15 +3138,15 @@ freeBindings(XML_Parser parser, BINDING *bindings)
while (bindings) {
BINDING *b = bindings;
- /* startNamespaceDeclHandler will have been called for this
+ /* m_startNamespaceDeclHandler will have been called for this
* binding in addBindings(), so call the end handler now.
*/
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
b->prefix->binding = b->prevPrefixBinding;
}
}
@@ -3180,7 +3166,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
const char *attStr, TAG_NAME *tagNamePtr,
BINDING **bindingsPtr)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
ELEMENT_TYPE *elementType;
int nDefaultAtts;
const XML_Char **appAtts; /* the attribute list for the application */
@@ -3203,43 +3189,43 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
sizeof(ELEMENT_TYPE));
if (!elementType)
return XML_ERROR_NO_MEMORY;
- if (ns && !setElementTypePrefix(parser, elementType))
+ if (parser->m_ns && !setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
nDefaultAtts = elementType->nDefaultAtts;
/* get the attributes from the tokenizer */
- n = XmlGetAttributes(enc, attStr, attsSize, atts);
- if (n + nDefaultAtts > attsSize) {
- int oldAttsSize = attsSize;
+ n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+ if (n + nDefaultAtts > parser->m_attsSize) {
+ int oldAttsSize = parser->m_attsSize;
ATTRIBUTE *temp;
#ifdef XML_ATTR_INFO
XML_AttrInfo *temp2;
#endif
- attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
- temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, parser->m_attsSize * sizeof(ATTRIBUTE));
if (temp == NULL) {
- attsSize = oldAttsSize;
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
- atts = temp;
+ parser->m_atts = temp;
#ifdef XML_ATTR_INFO
- temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+ temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo));
if (temp2 == NULL) {
- attsSize = oldAttsSize;
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
- attInfo = temp2;
+ parser->m_attInfo = temp2;
#endif
if (n > oldAttsSize)
- XmlGetAttributes(enc, attStr, n, atts);
+ XmlGetAttributes(enc, attStr, n, parser->m_atts);
}
- appAtts = (const XML_Char **)atts;
+ appAtts = (const XML_Char **)parser->m_atts;
for (i = 0; i < n; i++) {
- ATTRIBUTE *currAtt = &atts[i];
+ ATTRIBUTE *currAtt = &parser->m_atts[i];
#ifdef XML_ATTR_INFO
- XML_AttrInfo *currAttInfo = &attInfo[i];
+ XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
#endif
/* add the name and value to the attribute list */
ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
@@ -3248,25 +3234,25 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
if (!attId)
return XML_ERROR_NO_MEMORY;
#ifdef XML_ATTR_INFO
- currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+ currAttInfo->nameStart = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name);
currAttInfo->nameEnd = currAttInfo->nameStart +
XmlNameLength(enc, currAtt->name);
- currAttInfo->valueStart = parseEndByteIndex -
- (parseEndPtr - currAtt->valuePtr);
- currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+ currAttInfo->valueStart = parser->m_parseEndByteIndex -
+ (parser->m_parseEndPtr - currAtt->valuePtr);
+ currAttInfo->valueEnd = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->valueEnd);
#endif
/* Detect duplicate attributes by their QNames. This does not work when
namespace processing is turned on and different prefixes for the same
namespace are used. For this case we have a check further down.
*/
if ((attId->name)[-1]) {
- if (enc == encoding)
- eventPtr = atts[i].name;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = parser->m_atts[i].name;
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
(attId->name)[-1] = 1;
appAtts[attIndex++] = attId->name;
- if (!atts[i].normalized) {
+ if (!parser->m_atts[i].normalized) {
enum XML_Error result;
XML_Bool isCdata = XML_TRUE;
@@ -3283,20 +3269,20 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
/* normalize the attribute value */
result = storeAttributeValue(parser, enc, isCdata,
- atts[i].valuePtr, atts[i].valueEnd,
- &tempPool);
+ parser->m_atts[i].valuePtr, parser->m_atts[i].valueEnd,
+ &parser->m_tempPool);
if (result)
return result;
- appAtts[attIndex] = poolStart(&tempPool);
- poolFinish(&tempPool);
+ appAtts[attIndex] = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
}
else {
/* the value did not need normalizing */
- appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
- atts[i].valueEnd);
+ appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc, parser->m_atts[i].valuePtr,
+ parser->m_atts[i].valueEnd);
if (appAtts[attIndex] == 0)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
}
/* handle prefixed attribute names */
if (attId->prefix) {
@@ -3320,16 +3306,16 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
}
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
- nSpecifiedAtts = attIndex;
+ parser->m_nSpecifiedAtts = attIndex;
if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
for (i = 0; i < attIndex; i += 2)
if (appAtts[i] == elementType->idAtt->name) {
- idAttIndex = i;
+ parser->m_idAttIndex = i;
break;
}
}
else
- idAttIndex = -1;
+ parser->m_idAttIndex = -1;
/* do attribute defaulting */
for (i = 0; i < nDefaultAtts; i++) {
@@ -3363,33 +3349,33 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
i = 0;
if (nPrefixes) {
int j; /* hash table index */
- unsigned long version = nsAttsVersion;
- int nsAttsSize = (int)1 << nsAttsPower;
- unsigned char oldNsAttsPower = nsAttsPower;
+ unsigned long version = parser->m_nsAttsVersion;
+ int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
- if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ if ((nPrefixes << 1) >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
NS_ATT *temp;
/* hash table size must also be a power of 2 and >= 8 */
- while (nPrefixes >> nsAttsPower++);
- if (nsAttsPower < 3)
- nsAttsPower = 3;
- nsAttsSize = (int)1 << nsAttsPower;
- temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+ while (nPrefixes >> parser->m_nsAttsPower++);
+ if (parser->m_nsAttsPower < 3)
+ parser->m_nsAttsPower = 3;
+ nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT));
if (!temp) {
- /* Restore actual size of memory in nsAtts */
- nsAttsPower = oldNsAttsPower;
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
return XML_ERROR_NO_MEMORY;
}
- nsAtts = temp;
- version = 0; /* force re-initialization of nsAtts hash table */
+ parser->m_nsAtts = temp;
+ version = 0; /* force re-initialization of m_nsAtts hash table */
}
- /* using a version flag saves us from initializing nsAtts every time */
+ /* using a version flag saves us from initializing m_nsAtts every time */
if (!version) { /* initialize version flags when version wraps around */
version = INIT_ATTS_VERSION;
for (j = nsAttsSize; j != 0; )
- nsAtts[--j].version = version;
+ parser->m_nsAtts[--j].version = version;
}
- nsAttsVersion = --version;
+ parser->m_nsAttsVersion = --version;
/* expand prefixed names and check for duplicates */
for (; i < attIndex; i += 2) {
@@ -3429,7 +3415,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
for (j = 0; j < b->uriLen; j++) {
const XML_Char c = b->uri[j];
- if (!poolAppendChar(&tempPool, c))
+ if (!poolAppendChar(&parser->m_tempPool, c))
return XML_ERROR_NO_MEMORY;
}
@@ -3441,7 +3427,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
do { /* copies null terminator */
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
} while (*s++);
@@ -3453,40 +3439,40 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
unsigned char step = 0;
unsigned long mask = nsAttsSize - 1;
j = uriHash & mask; /* index into hash table */
- while (nsAtts[j].version == version) {
+ while (parser->m_nsAtts[j].version == version) {
/* for speed we compare stored hash values first */
- if (uriHash == nsAtts[j].hash) {
- const XML_Char *s1 = poolStart(&tempPool);
- const XML_Char *s2 = nsAtts[j].uriName;
+ if (uriHash == parser->m_nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&parser->m_tempPool);
+ const XML_Char *s2 = parser->m_nsAtts[j].uriName;
/* s1 is null terminated, but not s2 */
for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
if (*s1 == 0)
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
if (!step)
- step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower);
j < step ? (j += nsAttsSize - step) : (j -= step);
}
}
- if (ns_triplets) { /* append namespace separator and prefix */
- tempPool.ptr[-1] = namespaceSeparator;
+ if (parser->m_ns_triplets) { /* append namespace separator and prefix */
+ parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator;
s = b->prefix->name;
do {
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
} while (*s++);
}
/* store expanded name in attribute list */
- s = poolStart(&tempPool);
- poolFinish(&tempPool);
+ s = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
appAtts[i] = s;
/* fill empty slot with new version, uriName and hash value */
- nsAtts[j].version = version;
- nsAtts[j].hash = uriHash;
- nsAtts[j].uriName = s;
+ parser->m_nsAtts[j].version = version;
+ parser->m_nsAtts[j].hash = uriHash;
+ parser->m_nsAtts[j].uriName = s;
if (!--nPrefixes) {
i += 2;
@@ -3503,7 +3489,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
binding->attId->name[-1] = 0;
- if (!ns)
+ if (!parser->m_ns)
return XML_ERROR_NONE;
/* expand the element type name */
@@ -3522,7 +3508,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
else
return XML_ERROR_NONE;
prefixLen = 0;
- if (ns_triplets && binding->prefix->name) {
+ if (parser->m_ns_triplets && binding->prefix->name) {
for (; binding->prefix->name[prefixLen++];)
; /* prefixLen includes null terminator */
}
@@ -3535,24 +3521,24 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
n = i + binding->uriLen + prefixLen;
if (n > binding->uriAlloc) {
TAG *p;
- uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+ uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
if (!uri)
return XML_ERROR_NO_MEMORY;
binding->uriAlloc = n + EXPAND_SPARE;
memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
- for (p = tagStack; p; p = p->parent)
+ for (p = parser->m_tagStack; p; p = p->parent)
if (p->name.str == binding->uri)
p->name.str = uri;
- FREE(binding->uri);
+ FREE(parser, binding->uri);
binding->uri = uri;
}
- /* if namespaceSeparator != '\0' then uri includes it already */
+ /* if m_namespaceSeparator != '\0' then uri includes it already */
uri = binding->uri + binding->uriLen;
memcpy(uri, localPart, i * sizeof(XML_Char));
/* we always have a namespace separator between localPart and prefix */
if (prefixLen) {
uri += i - 1;
- *uri = namespaceSeparator; /* replace null terminator */
+ *uri = parser->m_namespaceSeparator; /* replace null terminator */
memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
}
tagNamePtr->str = binding->uri;
@@ -3630,48 +3616,48 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (isXMLNS)
return XML_ERROR_RESERVED_NAMESPACE_URI;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len++;
- if (freeBindingList) {
- b = freeBindingList;
+ if (parser->m_freeBindingList) {
+ b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
- XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+ XML_Char *temp = (XML_Char *)REALLOC(parser, b->uri,
sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
b->uri = temp;
b->uriAlloc = len + EXPAND_SPARE;
}
- freeBindingList = b->nextTagBinding;
+ parser->m_freeBindingList = b->nextTagBinding;
}
else {
- b = (BINDING *)MALLOC(sizeof(BINDING));
+ b = (BINDING *)MALLOC(parser, sizeof(BINDING));
if (!b)
return XML_ERROR_NO_MEMORY;
- b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+ b->uri = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (!b->uri) {
- FREE(b);
+ FREE(parser, b);
return XML_ERROR_NO_MEMORY;
}
b->uriAlloc = len + EXPAND_SPARE;
}
b->uriLen = len;
memcpy(b->uri, uri, len * sizeof(XML_Char));
- if (namespaceSeparator)
- b->uri[len - 1] = namespaceSeparator;
+ if (parser->m_namespaceSeparator)
+ b->uri[len - 1] = parser->m_namespaceSeparator;
b->prefix = prefix;
b->attId = attId;
b->prevPrefixBinding = prefix->binding;
/* NULL binding when default namespace undeclared */
- if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix)
prefix->binding = NULL;
else
prefix->binding = b;
b->nextTagBinding = *bindingsPtr;
*bindingsPtr = b;
/* if attId == NULL then we are not starting a namespace scope */
- if (attId && startNamespaceDeclHandler)
- startNamespaceDeclHandler(handlerArg, prefix->name,
+ if (attId && parser->m_startNamespaceDeclHandler)
+ parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
prefix->binding ? uri : 0);
return XML_ERROR_NONE;
}
@@ -3685,17 +3671,17 @@ cdataSectionProcessor(XML_Parser parser,
const char *end,
const char **endPtr)
{
- enum XML_Error result = doCdataSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doCdataSection(parser, parser->m_encoding, &start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- if (parentParser) { /* we are parsing an external entity */
- processor = externalEntityContentProcessor;
+ if (parser->m_parentParser) { /* we are parsing an external entity */
+ parser->m_processor = externalEntityContentProcessor;
return externalEntityContentProcessor(parser, start, end, endPtr);
}
else {
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, start, end, endPtr);
}
}
@@ -3716,14 +3702,14 @@ doCdataSection(XML_Parser parser,
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
*startPtr = NULL;
@@ -3734,51 +3720,51 @@ doCdataSection(XML_Parser parser,
*eventEndPP = next;
switch (tok) {
case XML_TOK_CDATA_SECT_CLOSE:
- if (endCdataSectionHandler)
- endCdataSectionHandler(handlerArg);
-#if 0
+ if (parser->m_endCdataSectionHandler)
+ parser->m_endCdataSectionHandler(parser->m_handlerArg);
+/* BEGIN disabled code */
/* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
+ else if (0 && parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0);
+/* END disabled code */
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_DATA_CHARS:
{
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
if (charDataHandler) {
if (MUST_CONVERT(enc, s)) {
for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = next;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
}
else
- charDataHandler(handlerArg,
+ charDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)next - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
@@ -3812,7 +3798,7 @@ doCdataSection(XML_Parser parser,
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
@@ -3835,12 +3821,12 @@ ignoreSectionProcessor(XML_Parser parser,
const char *end,
const char **endPtr)
{
- enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doIgnoreSection(parser, parser->m_encoding, &start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, start, end, endPtr);
}
return result;
@@ -3862,15 +3848,15 @@ doIgnoreSection(XML_Parser parser,
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
/* It's not entirely clear, but it seems the following two lines
* of code cannot be executed. The only occasions on which 'enc'
- * is not 'parser->m_encoding' are when this function is called
+ * is not 'encoding' are when this function is called
* from the internal entity processing, and IGNORE sections are an
* error in internal entities.
*
@@ -3879,8 +3865,8 @@ doIgnoreSection(XML_Parser parser,
*
* LCOV_EXCL_START
*/
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
/* LCOV_EXCL_STOP */
}
*eventPP = s;
@@ -3889,11 +3875,11 @@ doIgnoreSection(XML_Parser parser,
*eventEndPP = next;
switch (tok) {
case XML_TOK_IGNORE_SECT:
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
@@ -3937,27 +3923,27 @@ initializeEncoding(XML_Parser parser)
#ifdef XML_UNICODE
char encodingBuf[128];
/* See comments abount `protoclEncodingName` in parserInit() */
- if (!protocolEncodingName)
+ if (!parser->m_protocolEncodingName)
s = NULL;
else {
int i;
- for (i = 0; protocolEncodingName[i]; i++) {
+ for (i = 0; parser->m_protocolEncodingName[i]; i++) {
if (i == sizeof(encodingBuf) - 1
- || (protocolEncodingName[i] & ~0x7f) != 0) {
+ || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) {
encodingBuf[0] = '\0';
break;
}
- encodingBuf[i] = (char)protocolEncodingName[i];
+ encodingBuf[i] = (char)parser->m_protocolEncodingName[i];
}
encodingBuf[i] = '\0';
s = encodingBuf;
}
#else
- s = protocolEncodingName;
+ s = parser->m_protocolEncodingName;
#endif
- if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(&parser->m_initEncoding, &parser->m_encoding, s))
return XML_ERROR_NONE;
- return handleUnknownEncoding(parser, protocolEncodingName);
+ return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
}
static enum XML_Error
@@ -3971,13 +3957,13 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
const char *versionend;
const XML_Char *storedversion = NULL;
int standalone = -1;
- if (!(ns
+ if (!(parser->m_ns
? XmlParseXmlDeclNS
: XmlParseXmlDecl)(isGeneralTextEntity,
- encoding,
+ parser->m_encoding,
s,
next,
- &eventPtr,
+ &parser->m_eventPtr,
&version,
&versionend,
&encodingName,
@@ -3989,69 +3975,69 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
return XML_ERROR_XML_DECL;
}
if (!isGeneralTextEntity && standalone == 1) {
- _dtd->standalone = XML_TRUE;
+ parser->m_dtd->standalone = XML_TRUE;
#ifdef XML_DTD
- if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ if (parser->m_paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif /* XML_DTD */
}
- if (xmlDeclHandler) {
+ if (parser->m_xmlDeclHandler) {
if (encodingName != NULL) {
- storedEncName = poolStoreString(&temp2Pool,
- encoding,
+ storedEncName = poolStoreString(&parser->m_temp2Pool,
+ parser->m_encoding,
encodingName,
encodingName
- + XmlNameLength(encoding, encodingName));
+ + XmlNameLength(parser->m_encoding, encodingName));
if (!storedEncName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&temp2Pool);
+ poolFinish(&parser->m_temp2Pool);
}
if (version) {
- storedversion = poolStoreString(&temp2Pool,
- encoding,
+ storedversion = poolStoreString(&parser->m_temp2Pool,
+ parser->m_encoding,
version,
- versionend - encoding->minBytesPerChar);
+ versionend - parser->m_encoding->minBytesPerChar);
if (!storedversion)
return XML_ERROR_NO_MEMORY;
}
- xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+ parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName, standalone);
}
- else if (defaultHandler)
- reportDefault(parser, encoding, s, next);
- if (protocolEncodingName == NULL) {
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_protocolEncodingName == NULL) {
if (newEncoding) {
/* Check that the specified encoding does not conflict with what
* the parser has already deduced. Do we have the same number
* of bytes in the smallest representation of a character? If
* this is UTF-16, is it the same endianness?
*/
- if (newEncoding->minBytesPerChar != encoding->minBytesPerChar
+ if (newEncoding->minBytesPerChar != parser->m_encoding->minBytesPerChar
|| (newEncoding->minBytesPerChar == 2 &&
- newEncoding != encoding)) {
- eventPtr = encodingName;
+ newEncoding != parser->m_encoding)) {
+ parser->m_eventPtr = encodingName;
return XML_ERROR_INCORRECT_ENCODING;
}
- encoding = newEncoding;
+ parser->m_encoding = newEncoding;
}
else if (encodingName) {
enum XML_Error result;
if (!storedEncName) {
storedEncName = poolStoreString(
- &temp2Pool, encoding, encodingName,
- encodingName + XmlNameLength(encoding, encodingName));
+ &parser->m_temp2Pool, parser->m_encoding, encodingName,
+ encodingName + XmlNameLength(parser->m_encoding, encodingName));
if (!storedEncName)
return XML_ERROR_NO_MEMORY;
}
result = handleUnknownEncoding(parser, storedEncName);
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
if (result == XML_ERROR_UNKNOWN_ENCODING)
- eventPtr = encodingName;
+ parser->m_eventPtr = encodingName;
return result;
}
}
if (storedEncName || storedversion)
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
return XML_ERROR_NONE;
}
@@ -4059,7 +4045,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
{
- if (unknownEncodingHandler) {
+ if (parser->m_unknownEncodingHandler) {
XML_Encoding info;
int i;
for (i = 0; i < 256; i++)
@@ -4067,25 +4053,25 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
info.convert = NULL;
info.data = NULL;
info.release = NULL;
- if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+ if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData, encodingName,
&info)) {
ENCODING *enc;
- unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
- if (!unknownEncodingMem) {
+ parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
+ if (!parser->m_unknownEncodingMem) {
if (info.release)
info.release(info.data);
return XML_ERROR_NO_MEMORY;
}
- enc = (ns
+ enc = (parser->m_ns
? XmlInitUnknownEncodingNS
- : XmlInitUnknownEncoding)(unknownEncodingMem,
+ : XmlInitUnknownEncoding)(parser->m_unknownEncodingMem,
info.map,
info.convert,
info.data);
if (enc) {
- unknownEncodingData = info.data;
- unknownEncodingRelease = info.release;
- encoding = enc;
+ parser->m_unknownEncodingData = info.data;
+ parser->m_unknownEncodingRelease = info.release;
+ parser->m_encoding = enc;
return XML_ERROR_NONE;
}
}
@@ -4104,7 +4090,7 @@ prologInitProcessor(XML_Parser parser,
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, s, end, nextPtr);
}
@@ -4122,14 +4108,14 @@ externalParEntInitProcessor(XML_Parser parser,
/* we know now that XML_Parse(Buffer) has been called,
so we consider the external parameter entity read */
- _dtd->paramEntityRead = XML_TRUE;
+ parser->m_dtd->paramEntityRead = XML_TRUE;
- if (prologState.inEntityValue) {
- processor = entityValueInitProcessor;
+ if (parser->m_prologState.inEntityValue) {
+ parser->m_processor = entityValueInitProcessor;
return entityValueInitProcessor(parser, s, end, nextPtr);
}
else {
- processor = externalParEntProcessor;
+ parser->m_processor = externalParEntProcessor;
return externalParEntProcessor(parser, s, end, nextPtr);
}
}
@@ -4143,13 +4129,13 @@ entityValueInitProcessor(XML_Parser parser,
int tok;
const char *start = s;
const char *next = start;
- eventPtr = start;
+ parser->m_eventPtr = start;
for (;;) {
- tok = XmlPrologTok(encoding, start, end, &next);
- eventEndPtr = next;
+ tok = XmlPrologTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -4165,23 +4151,23 @@ entityValueInitProcessor(XML_Parser parser,
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, encoding, s, end);
+ return storeEntityValue(parser, parser->m_encoding, s, end);
}
else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
if (result != XML_ERROR_NONE)
return result;
- /* At this point, ps_parsing cannot be XML_SUSPENDED. For that
+ /* At this point, m_parsingStatus.parsing cannot be XML_SUSPENDED. For that
* to happen, a parameter entity parsing handler must have
* attempted to suspend the parser, which fails and raises an
* error. The parser can be aborted, but can't be suspended.
*/
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
*nextPtr = next;
/* stop scanning for text declaration - we found one */
- processor = entityValueProcessor;
+ parser->m_processor = entityValueProcessor;
return entityValueProcessor(parser, next, end, nextPtr);
}
/* If we are at the end of the buffer, this would cause XmlPrologTok to
@@ -4191,7 +4177,7 @@ entityValueInitProcessor(XML_Parser parser,
then, when this routine is entered the next time, XmlPrologTok will
return XML_TOK_INVALID, since the BOM is still in the buffer
*/
- else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ else if (tok == XML_TOK_BOM && next == end && !parser->m_parsingStatus.finalBuffer) {
*nextPtr = next;
return XML_ERROR_NONE;
}
@@ -4204,7 +4190,7 @@ entityValueInitProcessor(XML_Parser parser,
return XML_ERROR_SYNTAX;
}
start = next;
- eventPtr = start;
+ parser->m_eventPtr = start;
}
}
@@ -4217,9 +4203,9 @@ externalParEntProcessor(XML_Parser parser,
const char *next = s;
int tok;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -4241,12 +4227,12 @@ externalParEntProcessor(XML_Parser parser,
*/
else if (tok == XML_TOK_BOM) {
s = next;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
}
- processor = prologProcessor;
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ parser->m_processor = prologProcessor;
+ return doProlog(parser, parser->m_encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
static enum XML_Error PTRCALL
@@ -4257,13 +4243,13 @@ entityValueProcessor(XML_Parser parser,
{
const char *start = s;
const char *next = s;
- const ENCODING *enc = encoding;
+ const ENCODING *enc = parser->m_encoding;
int tok;
for (;;) {
tok = XmlPrologTok(enc, start, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -4294,9 +4280,9 @@ prologProcessor(XML_Parser parser,
const char **nextPtr)
{
const char *next = s;
- int tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
static enum XML_Error
@@ -4333,19 +4319,19 @@ doProlog(XML_Parser parser,
static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD * const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
enum XML_Content_Quant quant;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
for (;;) {
@@ -4372,7 +4358,7 @@ doProlog(XML_Parser parser,
case XML_TOK_NONE:
#ifdef XML_DTD
/* for internal PE NOT referenced between declarations */
- if (enc != encoding && !openInternalEntities->betweenDecl) {
+ if (enc != parser->m_encoding && !parser->m_openInternalEntities->betweenDecl) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -4380,8 +4366,8 @@ doProlog(XML_Parser parser,
complete markup, not only for external PEs, but also for
internal PEs if the reference occurs between declarations.
*/
- if (isParamEntity || enc != encoding) {
- if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
+ if (XmlTokenRole(&parser->m_prologState, XML_TOK_NONE, end, end, enc)
== XML_ROLE_ERROR)
return XML_ERROR_INCOMPLETE_PE;
*nextPtr = s;
@@ -4395,34 +4381,34 @@ doProlog(XML_Parser parser,
break;
}
}
- role = XmlTokenRole(&prologState, tok, s, next, enc);
+ role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
switch (role) {
case XML_ROLE_XML_DECL:
{
enum XML_Error result = processXmlDecl(parser, 0, s, next);
if (result != XML_ERROR_NONE)
return result;
- enc = encoding;
+ enc = parser->m_encoding;
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_DOCTYPE_NAME:
- if (startDoctypeDeclHandler) {
- doctypeName = poolStoreString(&tempPool, enc, s, next);
- if (!doctypeName)
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeName = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (!parser->m_doctypeName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- doctypePubid = NULL;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = NULL;
handleDefault = XML_FALSE;
}
- doctypeSysid = NULL; /* always initialize to NULL */
+ parser->m_doctypeSysid = NULL; /* always initialize to NULL */
break;
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
- if (startDoctypeDeclHandler) {
- startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
- doctypePubid, 1);
- doctypeName = NULL;
- poolClear(&tempPool);
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_startDoctypeDeclHandler(parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
+ parser->m_doctypePubid, 1);
+ parser->m_doctypeName = NULL;
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
@@ -4432,34 +4418,34 @@ doProlog(XML_Parser parser,
enum XML_Error result = processXmlDecl(parser, 1, s, next);
if (result != XML_ERROR_NONE)
return result;
- enc = encoding;
+ enc = parser->m_encoding;
handleDefault = XML_FALSE;
}
break;
#endif /* XML_DTD */
case XML_ROLE_DOCTYPE_PUBLIC_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
- declEntity = (ENTITY *)lookup(parser,
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_declEntity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
+ if (parser->m_startDoctypeDeclHandler) {
XML_Char *pubId;
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- pubId = poolStoreString(&tempPool, enc,
+ pubId = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!pubId)
return XML_ERROR_NO_MEMORY;
normalizePublicId(pubId);
- poolFinish(&tempPool);
- doctypePubid = pubId;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = pubId;
handleDefault = XML_FALSE;
goto alreadyChecked;
}
@@ -4468,7 +4454,7 @@ doProlog(XML_Parser parser,
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
alreadyChecked:
- if (dtd->keepProcessing && declEntity) {
+ if (dtd->keepProcessing && parser->m_declEntity) {
XML_Char *tem = poolStoreString(&dtd->pool,
enc,
s + enc->minBytesPerChar,
@@ -4476,28 +4462,31 @@ doProlog(XML_Parser parser,
if (!tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declEntity->publicId = tem;
+ parser->m_declEntity->publicId = tem;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_PUBLIC_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_PUBLIC_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_DOCTYPE_CLOSE:
- if (doctypeName) {
- startDoctypeDeclHandler(handlerArg, doctypeName,
- doctypeSysid, doctypePubid, 0);
- poolClear(&tempPool);
+ if (parser->m_doctypeName) {
+ parser->m_startDoctypeDeclHandler(parser->m_handlerArg, parser->m_doctypeName,
+ parser->m_doctypeSysid, parser->m_doctypePubid, 0);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
- /* doctypeSysid will be non-NULL in the case of a previous
- XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ /* parser->m_doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if parser->m_startDoctypeDeclHandler
was not set, indicating an external subset
*/
#ifdef XML_DTD
- if (doctypeSysid || useForeignDTD) {
+ if (parser->m_doctypeSysid || parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
+ if (parser->m_paramEntityParsing && parser->m_externalEntityRefHandler) {
ENTITY *entity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
@@ -4510,10 +4499,10 @@ doProlog(XML_Parser parser,
*/
return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
}
- if (useForeignDTD)
- entity->base = curBase;
+ if (parser->m_useForeignDTD)
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
@@ -4521,22 +4510,22 @@ doProlog(XML_Parser parser,
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
is no external subset and we must reset dtd->hasParamEntityRefs
*/
- else if (!doctypeSysid)
+ else if (!parser->m_doctypeSysid)
dtd->hasParamEntityRefs = hadParamEntityRefs;
/* end of DTD - no need to update dtd->keepProcessing */
}
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
}
#endif /* XML_DTD */
- if (endDoctypeDeclHandler) {
- endDoctypeDeclHandler(handlerArg);
+ if (parser->m_endDoctypeDeclHandler) {
+ parser->m_endDoctypeDeclHandler(parser->m_handlerArg);
handleDefault = XML_FALSE;
}
break;
@@ -4545,18 +4534,18 @@ doProlog(XML_Parser parser,
/* if there is no DOCTYPE declaration then now is the
last chance to read the foreign DTD
*/
- if (useForeignDTD) {
+ if (parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
+ if (parser->m_paramEntityParsing && parser->m_externalEntityRefHandler) {
ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
if (!entity)
return XML_ERROR_NO_MEMORY;
- entity->base = curBase;
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
@@ -4564,8 +4553,8 @@ doProlog(XML_Parser parser,
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
@@ -4577,55 +4566,55 @@ doProlog(XML_Parser parser,
}
}
#endif /* XML_DTD */
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, s, end, nextPtr);
case XML_ROLE_ATTLIST_ELEMENT_NAME:
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (!parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_NAME:
- declAttributeId = getAttributeId(parser, enc, s, next);
- if (!declAttributeId)
+ parser->m_declAttributeId = getAttributeId(parser, enc, s, next);
+ if (!parser->m_declAttributeId)
return XML_ERROR_NO_MEMORY;
- declAttributeIsCdata = XML_FALSE;
- declAttributeType = NULL;
- declAttributeIsId = XML_FALSE;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeType = NULL;
+ parser->m_declAttributeIsId = XML_FALSE;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
- declAttributeIsCdata = XML_TRUE;
- declAttributeType = atypeCDATA;
+ parser->m_declAttributeIsCdata = XML_TRUE;
+ parser->m_declAttributeType = atypeCDATA;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ID:
- declAttributeIsId = XML_TRUE;
- declAttributeType = atypeID;
+ parser->m_declAttributeIsId = XML_TRUE;
+ parser->m_declAttributeType = atypeID;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
- declAttributeType = atypeIDREF;
+ parser->m_declAttributeType = atypeIDREF;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
- declAttributeType = atypeIDREFS;
+ parser->m_declAttributeType = atypeIDREFS;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
- declAttributeType = atypeENTITY;
+ parser->m_declAttributeType = atypeENTITY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
- declAttributeType = atypeENTITIES;
+ parser->m_declAttributeType = atypeENTITIES;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
- declAttributeType = atypeNMTOKEN;
+ parser->m_declAttributeType = atypeNMTOKEN;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
- declAttributeType = atypeNMTOKENS;
+ parser->m_declAttributeType = atypeNMTOKENS;
checkAttListDeclHandler:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
- if (dtd->keepProcessing && attlistDeclHandler) {
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler) {
const XML_Char *prefix;
- if (declAttributeType) {
+ if (parser->m_declAttributeType) {
prefix = enumValueSep;
}
else {
@@ -4633,37 +4622,37 @@ doProlog(XML_Parser parser,
? notationPrefix
: enumValueStart);
}
- if (!poolAppendString(&tempPool, prefix))
+ if (!poolAppendString(&parser->m_tempPool, prefix))
return XML_ERROR_NO_MEMORY;
- if (!poolAppend(&tempPool, enc, s, next))
+ if (!poolAppend(&parser->m_tempPool, enc, s, next))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
+ parser->m_declAttributeType = parser->m_tempPool.start;
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
if (dtd->keepProcessing) {
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, declAttributeIsId,
+ if (!defineAttribute(parser->m_declElementType, parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata, parser->m_declAttributeIsId,
0, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
+ parser->m_attlistDeclHandler(parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType,
0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
@@ -4673,7 +4662,7 @@ doProlog(XML_Parser parser,
if (dtd->keepProcessing) {
const XML_Char *attVal;
enum XML_Error result =
- storeAttributeValue(parser, enc, declAttributeIsCdata,
+ storeAttributeValue(parser, enc, parser->m_declAttributeIsCdata,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
&dtd->pool);
@@ -4682,26 +4671,26 @@ doProlog(XML_Parser parser,
attVal = poolStart(&dtd->pool);
poolFinish(&dtd->pool);
/* ID attributes aren't allowed to have a default */
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, XML_FALSE, attVal, parser))
+ if (!defineAttribute(parser->m_declElementType, parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata, XML_FALSE, attVal, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
+ parser->m_attlistDeclHandler(parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType,
attVal,
role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
@@ -4711,18 +4700,18 @@ doProlog(XML_Parser parser,
enum XML_Error result = storeEntityValue(parser, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (declEntity) {
- declEntity->textPtr = poolStart(&dtd->entityValuePool);
- declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ if (parser->m_declEntity) {
+ parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ parser->m_declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
poolFinish(&dtd->entityValuePool);
- if (entityDeclHandler) {
+ if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
- declEntity->textPtr,
- declEntity->textLen,
- curBase, 0, 0, 0);
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->is_param,
+ parser->m_declEntity->textPtr,
+ parser->m_declEntity->textLen,
+ parser->m_curBase, 0, 0, 0);
handleDefault = XML_FALSE;
}
}
@@ -4734,97 +4723,100 @@ doProlog(XML_Parser parser,
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
- doctypeSysid = poolStoreString(&tempPool, enc,
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeSysid = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (doctypeSysid == NULL)
+ if (parser->m_doctypeSysid == NULL)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
#ifdef XML_DTD
else
- /* use externalSubsetName to make doctypeSysid non-NULL
- for the case where no startDoctypeDeclHandler is set */
- doctypeSysid = externalSubsetName;
+ /* use externalSubsetName to make parser->m_doctypeSysid non-NULL
+ for the case where no parser->m_startDoctypeDeclHandler is set */
+ parser->m_doctypeSysid = externalSubsetName;
#endif /* XML_DTD */
if (!dtd->standalone
#ifdef XML_DTD
- && !paramEntityParsing
+ && !parser->m_paramEntityParsing
#endif /* XML_DTD */
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
+ && parser->m_notStandaloneHandler
+ && !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
#ifndef XML_DTD
break;
#else /* XML_DTD */
- if (!declEntity) {
- declEntity = (ENTITY *)lookup(parser,
+ if (!parser->m_declEntity) {
+ parser->m_declEntity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- declEntity->publicId = NULL;
+ parser->m_declEntity->publicId = NULL;
}
- /* fall through */
#endif /* XML_DTD */
+ /* fall through */
case XML_ROLE_ENTITY_SYSTEM_ID:
- if (dtd->keepProcessing && declEntity) {
- declEntity->systemId = poolStoreString(&dtd->pool, enc,
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->systemId = poolStoreString(&dtd->pool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (!declEntity->systemId)
+ if (!parser->m_declEntity->systemId)
return XML_ERROR_NO_MEMORY;
- declEntity->base = curBase;
+ parser->m_declEntity->base = parser->m_curBase;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_SYSTEM_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_SYSTEM_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_COMPLETE:
- if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ if (dtd->keepProcessing && parser->m_declEntity && parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->is_param,
0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
0);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_NOTATION_NAME:
- if (dtd->keepProcessing && declEntity) {
- declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
- if (!declEntity->notation)
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+ if (!parser->m_declEntity->notation)
return XML_ERROR_NO_MEMORY;
poolFinish(&dtd->pool);
- if (unparsedEntityDeclHandler) {
+ if (parser->m_unparsedEntityDeclHandler) {
*eventEndPP = s;
- unparsedEntityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_unparsedEntityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
+ parser->m_declEntity->notation);
handleDefault = XML_FALSE;
}
- else if (entityDeclHandler) {
+ else if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
0,0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
+ parser->m_declEntity->notation);
handleDefault = XML_FALSE;
}
}
@@ -4832,36 +4824,36 @@ doProlog(XML_Parser parser,
case XML_ROLE_GENERAL_ENTITY_NAME:
{
if (XmlPredefinedEntityName(enc, s, next)) {
- declEntity = NULL;
+ parser->m_declEntity = NULL;
break;
}
if (dtd->keepProcessing) {
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
if (!name)
return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
else {
poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_FALSE;
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_FALSE;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
+ parser->m_declEntity->is_internal = !(parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
}
}
else {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
}
break;
@@ -4871,90 +4863,90 @@ doProlog(XML_Parser parser,
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
if (!name)
return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
name, sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
else {
poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_TRUE;
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_TRUE;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
+ parser->m_declEntity->is_internal = !(parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
}
}
else {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
#else /* not XML_DTD */
- declEntity = NULL;
+ parser->m_declEntity = NULL;
#endif /* XML_DTD */
break;
case XML_ROLE_NOTATION_NAME:
- declNotationPublicId = NULL;
- declNotationName = NULL;
- if (notationDeclHandler) {
- declNotationName = poolStoreString(&tempPool, enc, s, next);
- if (!declNotationName)
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declNotationName = NULL;
+ if (parser->m_notationDeclHandler) {
+ parser->m_declNotationName = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (!parser->m_declNotationName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_PUBLIC_ID:
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- if (declNotationName) { /* means notationDeclHandler != NULL */
- XML_Char *tem = poolStoreString(&tempPool,
+ if (parser->m_declNotationName) { /* means m_notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&parser->m_tempPool,
enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declNotationPublicId = tem;
- poolFinish(&tempPool);
+ parser->m_declNotationPublicId = tem;
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_SYSTEM_ID:
- if (declNotationName && notationDeclHandler) {
+ if (parser->m_declNotationName && parser->m_notationDeclHandler) {
const XML_Char *systemId
- = poolStoreString(&tempPool, enc,
+ = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!systemId)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
+ parser->m_notationDeclHandler(parser->m_handlerArg,
+ parser->m_declNotationName,
+ parser->m_curBase,
systemId,
- declNotationPublicId);
+ parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_NOTATION_NO_SYSTEM_ID:
- if (declNotationPublicId && notationDeclHandler) {
+ if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) {
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
+ parser->m_notationDeclHandler(parser->m_handlerArg,
+ parser->m_declNotationName,
+ parser->m_curBase,
0,
- declNotationPublicId);
+ parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_ERROR:
switch (tok) {
@@ -4971,45 +4963,45 @@ doProlog(XML_Parser parser,
case XML_ROLE_IGNORE_SECT:
{
enum XML_Error result;
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
handleDefault = XML_FALSE;
result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
if (result != XML_ERROR_NONE)
return result;
else if (!next) {
- processor = ignoreSectionProcessor;
+ parser->m_processor = ignoreSectionProcessor;
return result;
}
}
break;
#endif /* XML_DTD */
case XML_ROLE_GROUP_OPEN:
- if (prologState.level >= groupSize) {
- if (groupSize) {
- char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+ if (parser->m_prologState.level >= parser->m_groupSize) {
+ if (parser->m_groupSize) {
+ char *temp = (char *)REALLOC(parser, parser->m_groupConnector, parser->m_groupSize *= 2);
if (temp == NULL) {
- groupSize /= 2;
+ parser->m_groupSize /= 2;
return XML_ERROR_NO_MEMORY;
}
- groupConnector = temp;
+ parser->m_groupConnector = temp;
if (dtd->scaffIndex) {
- int *temp = (int *)REALLOC(dtd->scaffIndex,
- groupSize * sizeof(int));
+ int *temp = (int *)REALLOC(parser, dtd->scaffIndex,
+ parser->m_groupSize * sizeof(int));
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
dtd->scaffIndex = temp;
}
}
else {
- groupConnector = (char *)MALLOC(groupSize = 32);
- if (!groupConnector) {
- groupSize = 0;
+ parser->m_groupConnector = (char *)MALLOC(parser, parser->m_groupSize = 32);
+ if (!parser->m_groupConnector) {
+ parser->m_groupSize = 0;
return XML_ERROR_NO_MEMORY;
}
}
}
- groupConnector[prologState.level] = 0;
+ parser->m_groupConnector[parser->m_prologState.level] = 0;
if (dtd->in_eldecl) {
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
@@ -5017,37 +5009,37 @@ doProlog(XML_Parser parser,
dtd->scaffIndex[dtd->scaffLevel] = myindex;
dtd->scaffLevel++;
dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_GROUP_SEQUENCE:
- if (groupConnector[prologState.level] == ASCII_PIPE)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_PIPE)
return XML_ERROR_SYNTAX;
- groupConnector[prologState.level] = ASCII_COMMA;
- if (dtd->in_eldecl && elementDeclHandler)
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_COMMA;
+ if (dtd->in_eldecl && parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_GROUP_CHOICE:
- if (groupConnector[prologState.level] == ASCII_COMMA)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_COMMA)
return XML_ERROR_SYNTAX;
if (dtd->in_eldecl
- && !groupConnector[prologState.level]
+ && !parser->m_groupConnector[parser->m_prologState.level]
&& (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
!= XML_CTYPE_MIXED)
) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_CHOICE;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
- groupConnector[prologState.level] = ASCII_PIPE;
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_PIPE;
break;
case XML_ROLE_PARAM_ENTITY_REF:
#ifdef XML_DTD
case XML_ROLE_INNER_PARAM_ENTITY_REF:
dtd->hasParamEntityRefs = XML_TRUE;
- if (!paramEntityParsing)
+ if (!parser->m_paramEntityParsing)
dtd->keepProcessing = dtd->standalone;
else {
const XML_Char *name;
@@ -5063,9 +5055,9 @@ doProlog(XML_Parser parser,
if yes, check that the entity exists, and that it is internal,
otherwise call the skipped entity handler
*/
- if (prologState.documentEntity &&
+ if (parser->m_prologState.documentEntity &&
(dtd->standalone
- ? !openInternalEntities
+ ? !parser->m_openInternalEntities
: !dtd->hasParamEntityRefs)) {
if (!entity)
return XML_ERROR_UNDEFINED_ENTITY;
@@ -5096,8 +5088,8 @@ doProlog(XML_Parser parser,
else if (!entity) {
dtd->keepProcessing = dtd->standalone;
/* cannot report skipped entities in declarations */
- if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
- skippedEntityHandler(handlerArg, name, 1);
+ if ((role == XML_ROLE_PARAM_ENTITY_REF) && parser->m_skippedEntityHandler) {
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1);
handleDefault = XML_FALSE;
}
break;
@@ -5114,10 +5106,10 @@ doProlog(XML_Parser parser,
handleDefault = XML_FALSE;
break;
}
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
@@ -5139,17 +5131,17 @@ doProlog(XML_Parser parser,
}
#endif /* XML_DTD */
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
break;
/* Element declaration stuff */
case XML_ROLE_ELEMENT_NAME:
- if (elementDeclHandler) {
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ if (parser->m_elementDeclHandler) {
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (!parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
dtd->scaffLevel = 0;
dtd->scaffCount = 0;
@@ -5161,8 +5153,8 @@ doProlog(XML_Parser parser,
case XML_ROLE_CONTENT_ANY:
case XML_ROLE_CONTENT_EMPTY:
if (dtd->in_eldecl) {
- if (elementDeclHandler) {
- XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+ if (parser->m_elementDeclHandler) {
+ XML_Content * content = (XML_Content *) MALLOC(parser, sizeof(XML_Content));
if (!content)
return XML_ERROR_NO_MEMORY;
content->quant = XML_CQUANT_NONE;
@@ -5173,7 +5165,7 @@ doProlog(XML_Parser parser,
XML_CTYPE_ANY :
XML_CTYPE_EMPTY);
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, content);
+ parser->m_elementDeclHandler(parser->m_handlerArg, parser->m_declElementType->name, content);
handleDefault = XML_FALSE;
}
dtd->in_eldecl = XML_FALSE;
@@ -5184,7 +5176,7 @@ doProlog(XML_Parser parser,
if (dtd->in_eldecl) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_MIXED;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
@@ -5221,7 +5213,7 @@ doProlog(XML_Parser parser,
nameLen = 0;
for (; name[nameLen++]; );
dtd->contentStringLen += nameLen;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
@@ -5239,7 +5231,7 @@ doProlog(XML_Parser parser,
quant = XML_CQUANT_PLUS;
closeGroup:
if (dtd->in_eldecl) {
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
dtd->scaffLevel--;
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
@@ -5249,7 +5241,7 @@ doProlog(XML_Parser parser,
if (!model)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, model);
+ parser->m_elementDeclHandler(parser->m_handlerArg, parser->m_declElementType->name, model);
}
dtd->in_eldecl = XML_FALSE;
dtd->contentStringLen = 0;
@@ -5276,31 +5268,31 @@ doProlog(XML_Parser parser,
}
break;
case XML_ROLE_DOCTYPE_NONE:
- if (startDoctypeDeclHandler)
+ if (parser->m_startDoctypeDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ENTITY_NONE:
- if (dtd->keepProcessing && entityDeclHandler)
+ if (dtd->keepProcessing && parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_NOTATION_NONE:
- if (notationDeclHandler)
+ if (parser->m_notationDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTLIST_NONE:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ELEMENT_NONE:
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
} /* end of big switch */
- if (handleDefault && defaultHandler)
+ if (handleDefault && parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
@@ -5320,18 +5312,18 @@ epilogProcessor(XML_Parser parser,
const char *end,
const char **nextPtr)
{
- processor = epilogProcessor;
- eventPtr = s;
+ parser->m_processor = epilogProcessor;
+ parser->m_eventPtr = s;
for (;;) {
const char *next = NULL;
- int tok = XmlPrologTok(encoding, s, end, &next);
- eventEndPtr = next;
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
/* report partial linebreak - it might be the last token */
case -XML_TOK_PROLOG_S:
- if (defaultHandler) {
- reportDefault(parser, encoding, s, next);
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_defaultHandler) {
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
}
*nextPtr = next;
@@ -5340,28 +5332,28 @@ epilogProcessor(XML_Parser parser,
*nextPtr = s;
return XML_ERROR_NONE;
case XML_TOK_PROLOG_S:
- if (defaultHandler)
- reportDefault(parser, encoding, s, next);
+ if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
break;
case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, encoding, s, next))
+ if (!reportProcessingInstruction(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_COMMENT:
- if (!reportComment(parser, encoding, s, next))
+ if (!reportComment(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_INVALID:
- eventPtr = next;
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -5369,8 +5361,8 @@ epilogProcessor(XML_Parser parser,
default:
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
}
- eventPtr = s = next;
- switch (ps_parsing) {
+ parser->m_eventPtr = s = next;
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
@@ -5390,21 +5382,21 @@ processInternalEntity(XML_Parser parser, ENTITY *entity,
enum XML_Error result;
OPEN_INTERNAL_ENTITY *openEntity;
- if (freeInternalEntities) {
- openEntity = freeInternalEntities;
- freeInternalEntities = openEntity->next;
+ if (parser->m_freeInternalEntities) {
+ openEntity = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity->next;
}
else {
- openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+ openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
if (!openEntity)
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
entity->processed = 0;
- openEntity->next = openInternalEntities;
- openInternalEntities = openEntity;
+ openEntity->next = parser->m_openInternalEntities;
+ parser->m_openInternalEntities = openEntity;
openEntity->entity = entity;
- openEntity->startTagLevel = tagLevel;
+ openEntity->startTagLevel = parser->m_tagLevel;
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
@@ -5415,26 +5407,26 @@ processInternalEntity(XML_Parser parser, ENTITY *entity,
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok,
next, &next, XML_FALSE);
}
else
#endif /* XML_DTD */
- result = doContent(parser, tagLevel, internalEncoding, textStart,
+ result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding, textStart,
textEnd, &next, XML_FALSE);
if (result == XML_ERROR_NONE) {
- if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - textStart);
- processor = internalEntityProcessor;
+ parser->m_processor = internalEntityProcessor;
}
else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
}
return result;
@@ -5450,7 +5442,7 @@ internalEntityProcessor(XML_Parser parser,
const char *textStart, *textEnd;
const char *next;
enum XML_Error result;
- OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+ OPEN_INTERNAL_ENTITY *openEntity = parser->m_openInternalEntities;
if (!openEntity)
return XML_ERROR_UNEXPECTED_STATE;
@@ -5462,44 +5454,44 @@ internalEntityProcessor(XML_Parser parser,
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok,
next, &next, XML_FALSE);
}
else
#endif /* XML_DTD */
- result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+ result = doContent(parser, openEntity->startTagLevel, parser->m_internalEncoding,
textStart, textEnd, &next, XML_FALSE);
if (result != XML_ERROR_NONE)
return result;
- else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ else if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - (char *)entity->textPtr);
return result;
}
else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
#ifdef XML_DTD
if (entity->is_param) {
int tok;
- processor = prologProcessor;
- tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next, nextPtr,
- (XML_Bool)!ps_finalBuffer);
+ parser->m_processor = prologProcessor;
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
else
#endif /* XML_DTD */
{
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
/* see externalEntityContentProcessor vs contentProcessor */
- return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, s, end,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
}
@@ -5509,7 +5501,7 @@ errorProcessor(XML_Parser parser,
const char *UNUSED_P(end),
const char **UNUSED_P(nextPtr))
{
- return errorCode;
+ return parser->m_errorCode;
}
static enum XML_Error
@@ -5533,7 +5525,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end,
STRING_POOL *pool)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
for (;;) {
const char *next;
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
@@ -5541,12 +5533,12 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
case XML_TOK_NONE:
return XML_ERROR_NONE;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_CHAR_REF:
{
@@ -5554,8 +5546,8 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
int i;
int n = XmlCharRefNumber(enc, ptr);
if (n < 0) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_BAD_CHAR_REF;
}
if (!isCdata
@@ -5605,25 +5597,25 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
return XML_ERROR_NO_MEMORY;
break;
}
- name = poolStoreString(&temp2Pool, enc,
+ name = poolStoreString(&parser->m_temp2Pool, enc,
ptr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!name)
return XML_ERROR_NO_MEMORY;
entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
- poolDiscard(&temp2Pool);
+ poolDiscard(&parser->m_temp2Pool);
/* First, determine if a check for an existing declaration is needed;
if yes, check that the entity exists, and that it is internal.
*/
if (pool == &dtd->pool) /* are we called from prolog? */
checkEntityDecl =
#ifdef XML_DTD
- prologState.documentEntity &&
+ parser->m_prologState.documentEntity &&
#endif /* XML_DTD */
(dtd->standalone
- ? !openInternalEntities
+ ? !parser->m_openInternalEntities
: !dtd->hasParamEntityRefs);
- else /* if (pool == &tempPool): we are called from content */
+ else /* if (pool == &parser->m_tempPool): we are called from content */
checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
if (checkEntityDecl) {
if (!entity)
@@ -5633,19 +5625,19 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
}
else if (!entity) {
/* Cannot report skipped entity here - see comments on
- skippedEntityHandler.
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
+ parser->m_skippedEntityHandler.
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
*/
/* Cannot call the default handler because this would be
out of sync with the call to the startElementHandler.
- if ((pool == &tempPool) && defaultHandler)
+ if ((pool == &parser->m_tempPool) && parser->m_defaultHandler)
reportDefault(parser, enc, ptr, next);
*/
break;
}
if (entity->open) {
- if (enc == encoding) {
+ if (enc == parser->m_encoding) {
/* It does not appear that this line can be executed.
*
* The "if (entity->open)" check catches recursive entity
@@ -5663,25 +5655,25 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
* we keep the line and merely exclude it from coverage
* tests.
*/
- eventPtr = ptr; /* LCOV_EXCL_LINE */
+ parser->m_eventPtr = ptr; /* LCOV_EXCL_LINE */
}
return XML_ERROR_RECURSIVE_ENTITY_REF;
}
if (entity->notation) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_BINARY_ENTITY_REF;
}
if (!entity->textPtr) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
}
else {
enum XML_Error result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = XML_TRUE;
- result = appendAttributeValue(parser, internalEncoding, isCdata,
+ result = appendAttributeValue(parser, parser->m_internalEncoding, isCdata,
(char *)entity->textPtr,
(char *)textEnd, pool);
entity->open = XML_FALSE;
@@ -5702,8 +5694,8 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
*
* LCOV_EXCL_START
*/
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_UNEXPECTED_STATE;
/* LCOV_EXCL_STOP */
}
@@ -5718,12 +5710,12 @@ storeEntityValue(XML_Parser parser,
const char *entityTextPtr,
const char *entityTextEnd)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
#ifdef XML_DTD
- int oldInEntityValue = prologState.inEntityValue;
- prologState.inEntityValue = 1;
+ int oldInEntityValue = parser->m_prologState.inEntityValue;
+ parser->m_prologState.inEntityValue = 1;
#endif /* XML_DTD */
/* never return Null for the value argument in EntityDeclHandler,
since this would indicate an external entity; therefore we
@@ -5739,10 +5731,10 @@ storeEntityValue(XML_Parser parser,
switch (tok) {
case XML_TOK_PARAM_ENTITY_REF:
#ifdef XML_DTD
- if (isParamEntity || enc != encoding) {
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
const XML_Char *name;
ENTITY *entity;
- name = poolStoreString(&tempPool, enc,
+ name = poolStoreString(&parser->m_tempPool, enc,
entityTextPtr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!name) {
@@ -5750,28 +5742,28 @@ storeEntityValue(XML_Parser parser,
goto endEntityValue;
}
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
if (!entity) {
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
/* cannot report skipped entity here - see comments on
- skippedEntityHandler
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
+ parser->m_skippedEntityHandler
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
*/
dtd->keepProcessing = dtd->standalone;
goto endEntityValue;
}
if (entity->open) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_RECURSIVE_ENTITY_REF;
goto endEntityValue;
}
if (entity->systemId) {
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
@@ -5790,7 +5782,7 @@ storeEntityValue(XML_Parser parser,
else {
entity->open = XML_TRUE;
result = storeEntityValue(parser,
- internalEncoding,
+ parser->m_internalEncoding,
(char *)entity->textPtr,
(char *)(entity->textPtr
+ entity->textLen));
@@ -5803,7 +5795,7 @@ storeEntityValue(XML_Parser parser,
#endif /* XML_DTD */
/* In the internal subset, PE references are not legal
within markup declarations, e.g entity values in this case. */
- eventPtr = entityTextPtr;
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_PARAM_ENTITY_REF;
goto endEntityValue;
case XML_TOK_NONE:
@@ -5832,8 +5824,8 @@ storeEntityValue(XML_Parser parser,
int i;
int n = XmlCharRefNumber(enc, entityTextPtr);
if (n < 0) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_BAD_CHAR_REF;
goto endEntityValue;
}
@@ -5857,13 +5849,13 @@ storeEntityValue(XML_Parser parser,
}
break;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
default:
@@ -5874,8 +5866,8 @@ storeEntityValue(XML_Parser parser,
*
* LCOV_EXCL_START
*/
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_UNEXPECTED_STATE;
goto endEntityValue;
/* LCOV_EXCL_STOP */
@@ -5884,7 +5876,7 @@ storeEntityValue(XML_Parser parser,
}
endEntityValue:
#ifdef XML_DTD
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
#endif /* XML_DTD */
return result;
}
@@ -5919,25 +5911,25 @@ reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
const XML_Char *target;
XML_Char *data;
const char *tem;
- if (!processingInstructionHandler) {
- if (defaultHandler)
+ if (!parser->m_processingInstructionHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
start += enc->minBytesPerChar * 2;
tem = start + XmlNameLength(enc, start);
- target = poolStoreString(&tempPool, enc, start, tem);
+ target = poolStoreString(&parser->m_tempPool, enc, start, tem);
if (!target)
return 0;
- poolFinish(&tempPool);
- data = poolStoreString(&tempPool, enc,
+ poolFinish(&parser->m_tempPool);
+ data = poolStoreString(&parser->m_tempPool, enc,
XmlSkipS(enc, tem),
end - enc->minBytesPerChar*2);
if (!data)
return 0;
normalizeLines(data);
- processingInstructionHandler(handlerArg, target, data);
- poolClear(&tempPool);
+ parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
@@ -5946,20 +5938,20 @@ reportComment(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end)
{
XML_Char *data;
- if (!commentHandler) {
- if (defaultHandler)
+ if (!parser->m_commentHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
- data = poolStoreString(&tempPool,
+ data = poolStoreString(&parser->m_tempPool,
enc,
start + enc->minBytesPerChar * 4,
end - enc->minBytesPerChar * 3);
if (!data)
return 0;
normalizeLines(data);
- commentHandler(handlerArg, data);
- poolClear(&tempPool);
+ parser->m_commentHandler(parser->m_handlerArg, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
@@ -5971,9 +5963,9 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
enum XML_Convert_Result convert_res;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
/* To get here, two things must be true; the parser must be
@@ -5992,20 +5984,20 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
*
* LCOV_EXCL_START
*/
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
/* LCOV_EXCL_STOP */
}
do {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
- defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
*eventPP = s;
} while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
}
else
- defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+ parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
}
@@ -6027,16 +6019,18 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
if (type->nDefaultAtts == type->allocDefaultAtts) {
if (type->allocDefaultAtts == 0) {
type->allocDefaultAtts = 8;
- type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(parser, type->allocDefaultAtts
* sizeof(DEFAULT_ATTRIBUTE));
- if (!type->defaultAtts)
+ if (!type->defaultAtts) {
+ type->allocDefaultAtts = 0;
return 0;
+ }
}
else {
DEFAULT_ATTRIBUTE *temp;
int count = type->allocDefaultAtts * 2;
temp = (DEFAULT_ATTRIBUTE *)
- REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ REALLOC(parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
if (temp == NULL)
return 0;
type->allocDefaultAtts = count;
@@ -6056,7 +6050,7 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
static int
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name;
for (name = elementType->name; *name; name++) {
if (*name == XML_T(ASCII_COLON)) {
@@ -6077,7 +6071,7 @@ setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
else
poolDiscard(&dtd->pool);
elementType->prefix = prefix;
-
+ break;
}
}
return 1;
@@ -6087,7 +6081,7 @@ static ATTRIBUTE_ID *
getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
ATTRIBUTE_ID *id;
const XML_Char *name;
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
@@ -6104,7 +6098,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
poolDiscard(&dtd->pool);
else {
poolFinish(&dtd->pool);
- if (!ns)
+ if (!parser->m_ns)
;
else if (name[0] == XML_T(ASCII_x)
&& name[1] == XML_T(ASCII_m)
@@ -6151,20 +6145,20 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
static const XML_Char *
getContext(XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
HASH_TABLE_ITER iter;
XML_Bool needSep = XML_FALSE;
if (dtd->defaultPrefix.binding) {
int i;
int len;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = dtd->defaultPrefix.binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
for (i = 0; i < len; i++) {
- if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) {
+ if (!poolAppendChar(&parser->m_tempPool, dtd->defaultPrefix.binding->uri[i])) {
/* Because of memory caching, I don't believe this line can be
* executed.
*
@@ -6207,18 +6201,18 @@ getContext(XML_Parser parser)
*/
continue; /* LCOV_EXCL_LINE */
}
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (needSep && !poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = prefix->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return NULL;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = prefix->binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ if (!poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i]))
return NULL;
needSep = XML_TRUE;
}
@@ -6232,73 +6226,73 @@ getContext(XML_Parser parser)
break;
if (!e->open)
continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (needSep && !poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = e->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return 0;
needSep = XML_TRUE;
}
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return NULL;
- return tempPool.start;
+ return parser->m_tempPool.start;
}
static XML_Bool
setContext(XML_Parser parser, const XML_Char *context)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *s = context;
while (*context != XML_T('\0')) {
if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
ENTITY *e;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+ e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&parser->m_tempPool), 0);
if (e)
e->open = XML_TRUE;
if (*s != XML_T('\0'))
s++;
context = s;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
else if (*s == XML_T(ASCII_EQUALS)) {
PREFIX *prefix;
- if (poolLength(&tempPool) == 0)
+ if (poolLength(&parser->m_tempPool) == 0)
prefix = &dtd->defaultPrefix;
else {
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&parser->m_tempPool),
sizeof(PREFIX));
if (!prefix)
return XML_FALSE;
- if (prefix->name == poolStart(&tempPool)) {
+ if (prefix->name == poolStart(&parser->m_tempPool)) {
prefix->name = poolCopyString(&dtd->pool, prefix->name);
if (!prefix->name)
return XML_FALSE;
}
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
for (context = s + 1;
*context != CONTEXT_SEP && *context != XML_T('\0');
context++)
- if (!poolAppendChar(&tempPool, *context))
+ if (!poolAppendChar(&parser->m_tempPool, *context))
return XML_FALSE;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
- &inheritedBindings) != XML_ERROR_NONE)
+ if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool),
+ &parser->m_inheritedBindings) != XML_ERROR_NONE)
return XML_FALSE;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
if (*context != XML_T('\0'))
++context;
s = context;
}
else {
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_FALSE;
s++;
}
@@ -6663,7 +6657,6 @@ hash(XML_Parser parser, KEY s)
{
struct siphash state;
struct sipkey key;
- (void)sip_tobin;
(void)sip24_valid;
copy_salt_to_sipkey(parser, &key);
sip24_init(&state, &key);
@@ -6983,8 +6976,8 @@ poolGrow(STRING_POOL *pool)
int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
size_t bytesToAllocate;
- // NOTE: Needs to be calculated prior to calling `realloc`
- // to avoid dangling pointers:
+ /* NOTE: Needs to be calculated prior to calling `realloc`
+ to avoid dangling pointers: */
const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
if (blockSize < 0) {
@@ -7062,12 +7055,12 @@ poolGrow(STRING_POOL *pool)
static int FASTCALL
nextScaffoldPart(XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
CONTENT_SCAFFOLD * me;
int next;
if (!dtd->scaffIndex) {
- dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+ dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
if (!dtd->scaffIndex)
return -1;
dtd->scaffIndex[0] = 0;
@@ -7077,13 +7070,13 @@ nextScaffoldPart(XML_Parser parser)
CONTENT_SCAFFOLD *temp;
if (dtd->scaffold) {
temp = (CONTENT_SCAFFOLD *)
- REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ REALLOC(parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
dtd->scaffSize *= 2;
}
else {
- temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+ temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS
* sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
@@ -7114,7 +7107,7 @@ build_node(XML_Parser parser,
XML_Content **contpos,
XML_Char **strpos)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
dest->type = dtd->scaffold[src_node].type;
dest->quant = dtd->scaffold[src_node].quant;
if (dest->type == XML_CTYPE_NAME) {
@@ -7148,14 +7141,14 @@ build_node(XML_Parser parser,
static XML_Content *
build_model (XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
XML_Content *ret;
XML_Content *cpos;
XML_Char * str;
int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ (dtd->contentStringLen * sizeof(XML_Char)));
- ret = (XML_Content *)MALLOC(allocsize);
+ ret = (XML_Content *)MALLOC(parser, allocsize);
if (!ret)
return NULL;
@@ -7172,7 +7165,7 @@ getElementType(XML_Parser parser,
const char *ptr,
const char *end)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
ELEMENT_TYPE *ret;
diff --git a/Utilities/cmexpat/lib/xmlrole.c b/Utilities/cmexpat/lib/xmlrole.c
index c809ee514..708507d57 100644
--- a/Utilities/cmexpat/lib/xmlrole.c
+++ b/Utilities/cmexpat/lib/xmlrole.c
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stddef.h>
diff --git a/Utilities/cmexpat/lib/xmlrole.h b/Utilities/cmexpat/lib/xmlrole.h
index 4dd9f06f9..e5f048eab 100644
--- a/Utilities/cmexpat/lib/xmlrole.h
+++ b/Utilities/cmexpat/lib/xmlrole.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XmlRole_INCLUDED
diff --git a/Utilities/cmexpat/lib/xmltok.c b/Utilities/cmexpat/lib/xmltok.c
index db4a5c8ca..6b415d839 100644
--- a/Utilities/cmexpat/lib/xmltok.c
+++ b/Utilities/cmexpat/lib/xmltok.c
@@ -1,8 +1,47 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stddef.h>
+#include <string.h> /* memcpy */
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
+ /* for vs2012/11.0/1700 and earlier Visual Studio compilers */
+# define bool int
+# define false 0
+# define true 1
+#else
+# include <stdbool.h>
+#endif
+
#ifdef _WIN32
#include "winconfig.h"
@@ -27,7 +66,6 @@
{ PREFIX(prologTok), PREFIX(contentTok), \
PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
{ PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
- PREFIX(sameName), \
PREFIX(nameMatchesAscii), \
PREFIX(nameLength), \
PREFIX(skipS), \
@@ -324,7 +362,7 @@ enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
};
void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
+_INTERNAL_trim_to_complete_utf8_characters(const char * from, const char ** fromLimRef)
{
const char * fromLim = *fromLimRef;
size_t walked = 0;
@@ -363,22 +401,37 @@ utf8_toUtf8(const ENCODING *UNUSED_P(enc),
const char **fromP, const char *fromLim,
char **toP, const char *toLim)
{
- char *to;
- const char *from;
- const char *fromLimInitial = fromLim;
+ bool input_incomplete = false;
+ bool output_exhausted = false;
+
+ /* Avoid copying partial characters (due to limited space). */
+ const ptrdiff_t bytesAvailable = fromLim - *fromP;
+ const ptrdiff_t bytesStorable = toLim - *toP;
+ if (bytesAvailable > bytesStorable) {
+ fromLim = *fromP + bytesStorable;
+ output_exhausted = true;
+ }
- /* Avoid copying partial characters. */
- align_limit_to_full_utf8_characters(*fromP, &fromLim);
+ /* Avoid copying partial characters (from incomplete input). */
+ {
+ const char * const fromLimBefore = fromLim;
+ _INTERNAL_trim_to_complete_utf8_characters(*fromP, &fromLim);
+ if (fromLim < fromLimBefore) {
+ input_incomplete = true;
+ }
+ }
- for (to = *toP, from = *fromP; (from < fromLim) && (to < toLim); from++, to++)
- *to = *from;
- *fromP = from;
- *toP = to;
+ {
+ const ptrdiff_t bytesToCopy = fromLim - *fromP;
+ memcpy(*toP, *fromP, bytesToCopy);
+ *fromP += bytesToCopy;
+ *toP += bytesToCopy;
+ }
- if (fromLim < fromLimInitial)
- return XML_CONVERT_INPUT_INCOMPLETE;
- else if ((to == toLim) && (from < fromLim))
+ if (output_exhausted) /* needs to go first */
return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else if (input_incomplete)
+ return XML_CONVERT_INPUT_INCOMPLETE;
else
return XML_CONVERT_COMPLETED;
}
@@ -1411,9 +1464,8 @@ unknown_toUtf8(const ENCODING *enc,
return XML_CONVERT_OUTPUT_EXHAUSTED;
(*fromP)++;
}
- do {
- *(*toP)++ = *utf8++;
- } while (--n != 0);
+ memcpy(*toP, utf8, n);
+ *toP += n;
}
}
diff --git a/Utilities/cmexpat/lib/xmltok.h b/Utilities/cmexpat/lib/xmltok.h
index 752007e8b..50926f38a 100644
--- a/Utilities/cmexpat/lib/xmltok.h
+++ b/Utilities/cmexpat/lib/xmltok.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XmlTok_INCLUDED
@@ -139,9 +167,6 @@ enum XML_Convert_Result {
struct encoding {
SCANNER scanners[XML_N_STATES];
SCANNER literalScanners[XML_N_LITERAL_TYPES];
- int (PTRCALL *sameName)(const ENCODING *,
- const char *,
- const char *);
int (PTRCALL *nameMatchesAscii)(const ENCODING *,
const char *,
const char *,
@@ -232,8 +257,6 @@ struct encoding {
#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
-#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
-
#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
diff --git a/Utilities/cmexpat/lib/xmltok_impl.c b/Utilities/cmexpat/lib/xmltok_impl.c
index 4fa1ff679..4d9ae7dc3 100644
--- a/Utilities/cmexpat/lib/xmltok_impl.c
+++ b/Utilities/cmexpat/lib/xmltok_impl.c
@@ -1,8 +1,35 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/* This file is included!
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* This file is included! */
#ifdef XML_TOK_IMPL_C
#ifndef IS_INVALID_CHAR
@@ -47,6 +74,7 @@
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
+ /* fall through */ \
case BT_NMSTRT: \
case BT_HEX: \
case BT_DIGIT: \
@@ -75,6 +103,7 @@
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
+ /* fall through */ \
case BT_NMSTRT: \
case BT_HEX: \
ptr += MINBPC(enc); \
@@ -575,7 +604,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_INVALID;
}
}
- /* fall through */
+ /* fall through */
case BT_EQUALS:
{
int open;
@@ -1415,6 +1444,7 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
case BT_NMSTRT:
if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
break;
+ /* fall through */
default:
switch (BYTE_TO_ASCII(enc, ptr)) {
case 0x24: /* $ */
@@ -1626,87 +1656,14 @@ PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
return 0;
}
-/* This function does not appear to be called from anywhere within the
- * library code. It is used via the macro XmlSameName(), which is
- * defined but never used. Since it appears in the encoding function
- * table, removing it is not a thing to be undertaken lightly. For
- * the moment, we simply exclude it from coverage tests.
- *
- * LCOV_EXCL_START
- */
-static int PTRCALL
-PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
-{
- for (;;) {
- switch (BYTE_TYPE(enc, ptr1)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (*ptr1++ != *ptr2++) \
- return 0;
- LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
-#undef LEAD_CASE
- /* fall through */
- if (*ptr1++ != *ptr2++)
- return 0;
- break;
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 1) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 2) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 3) {
- if (*ptr2++ != *ptr1++)
- return 0;
- }
- }
- }
- break;
- default:
- if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
- return 1;
- switch (BYTE_TYPE(enc, ptr2)) {
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- return 0;
- default:
- return 1;
- }
- }
- }
- /* not reached */
-}
-/* LCOV_EXCL_STOP */
-
static int PTRCALL
PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
const char *end1, const char *ptr2)
{
for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
if (end1 - ptr1 < MINBPC(enc)) {
- /* This line cannot be executed. THe incoming data has already
- * been tokenized once, so imcomplete characters like this have
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
* already been eliminated from the input. Retaining the
* paranoia check is still valuable, however.
*/
diff --git a/Utilities/cmexpat/lib/xmltok_impl.h b/Utilities/cmexpat/lib/xmltok_impl.h
index da0ea60a6..a6420f48e 100644
--- a/Utilities/cmexpat/lib/xmltok_impl.h
+++ b/Utilities/cmexpat/lib/xmltok_impl.h
@@ -1,6 +1,33 @@
/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
enum {
diff --git a/Utilities/cmexpat/lib/xmltok_ns.c b/Utilities/cmexpat/lib/xmltok_ns.c
index c3b88fdf4..23d31e8e4 100644
--- a/Utilities/cmexpat/lib/xmltok_ns.c
+++ b/Utilities/cmexpat/lib/xmltok_ns.c
@@ -1,8 +1,35 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/* This file is included!
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* This file is included! */
#ifdef XML_TOK_NS_C
const ENCODING *
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
index ef370cc2c..764be8d55 100644
--- a/Utilities/cmjsoncpp/CMakeLists.txt
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -2,7 +2,7 @@ project(JsonCpp CXX)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_CXX_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall")
diff --git a/Utilities/cmjsoncpp/include/json/config.h b/Utilities/cmjsoncpp/include/json/config.h
index eb52e71e4..2cc8462b3 100644
--- a/Utilities/cmjsoncpp/include/json/config.h
+++ b/Utilities/cmjsoncpp/include/json/config.h
@@ -5,13 +5,14 @@
#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
-#include <stddef.h>
-#include <string> //typedef String
-#include <stdint.h> //typedef int64_t, uint64_t
// Include KWSys Large File Support configuration.
#include <cmsys/Configure.h>
+#include <stddef.h>
+#include <string> //typedef String
+#include <stdint.h> //typedef int64_t, uint64_t
+
#if defined(_MSC_VER)
# pragma warning(push,1)
#endif
@@ -78,11 +79,6 @@
# pragma warning(disable : 4786)
# endif // MSVC 6
-# if _MSC_VER >= 1500 // MSVC 2008
- /// Indicates that the following function is deprecated.
-# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
-# endif
-
#endif // defined(_MSC_VER)
// In c++11 the override keyword allows you to explicity define that a function
@@ -136,7 +132,10 @@
# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
# endif // GNUC version
-#endif // __clang__ || __GNUC__
+#elif defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
+ /// Indicates that the following function is deprecated.
+# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif // __clang__ || __GNUC__ || _MSC_VER
#undef JSONCPP_DEPRECATED // no deprecations in CMake copy
#if !defined(JSONCPP_DEPRECATED)
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index d7af6e2b6..60c8316e3 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -60,7 +60,7 @@ SET(CMAKE_REQUIRED_FLAGS)
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -376,6 +376,7 @@ IF(LZ4_FOUND)
ENDIF(LZ4_FOUND)
MARK_AS_ADVANCED(CLEAR LZ4_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR LZ4_LIBRARY)
+ENDIF()
#
# Find Zstd
#
@@ -392,16 +393,13 @@ IF(ZSTD_FOUND)
SET(HAVE_ZSTD_H 1)
INCLUDE_DIRECTORIES(${ZSTD_INCLUDE_DIR})
LIST(APPEND ADDITIONAL_LIBS ${ZSTD_LIBRARY})
- SET(CMAKE_REQUIRED_LIBRARIES ${ZSTD_LIBRARY})
- SET(CMAKE_REQUIRED_INCLUDES ${ZSTD_INCLUDE_DIR})
- CHECK_FUNCTION_EXISTS(ZSTD_compressStream HAVE_LIBZSTD)
+ SET(HAVE_LIBZSTD 1)
#
# TODO: test for static library.
#
ENDIF(ZSTD_FOUND)
MARK_AS_ADVANCED(CLEAR ZSTD_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR ZSTD_LIBRARY)
-ENDIF()
#
# Check headers
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
index c8bb36be7..451370693 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
@@ -45,7 +45,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#endif
#if HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
#endif
#include "archive.h"
diff --git a/Utilities/cmlibarchive/libarchive/archive_version_details.c b/Utilities/cmlibarchive/libarchive/archive_version_details.c
index e773e5e45..b9af6d781 100644
--- a/Utilities/cmlibarchive/libarchive/archive_version_details.c
+++ b/Utilities/cmlibarchive/libarchive/archive_version_details.c
@@ -46,7 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#include <lz4.h>
#endif
#ifdef HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
#endif
#include "archive.h"
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
index 671fc6aff..251b17da5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#endif
#ifdef HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
#endif
#include "archive.h"
diff --git a/Utilities/cmliblzma/CMakeLists.txt b/Utilities/cmliblzma/CMakeLists.txt
index e9f88266d..b443fd6bc 100644
--- a/Utilities/cmliblzma/CMakeLists.txt
+++ b/Utilities/cmliblzma/CMakeLists.txt
@@ -183,7 +183,7 @@ INCLUDE_DIRECTORIES(
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibrhash/CMakeLists.txt b/Utilities/cmlibrhash/CMakeLists.txt
index aa280554c..6067b7dcb 100644
--- a/Utilities/cmlibrhash/CMakeLists.txt
+++ b/Utilities/cmlibrhash/CMakeLists.txt
@@ -2,7 +2,7 @@ project(librhash C)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index a62c516ef..2e781f155 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -2,7 +2,7 @@ project(libuv C)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h
index 7cac1f988..be741dcb7 100644
--- a/Utilities/cmlibuv/src/unix/atomic-ops.h
+++ b/Utilities/cmlibuv/src/unix/atomic-ops.h
@@ -37,7 +37,7 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
: "r" (newval), "0" (oldval)
: "memory");
return out;
-#elif defined(_AIX) && defined(__xlC__)
+#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
const int out = (*(volatile int*) ptr);
__compare_and_swap(ptr, &oldval, newval);
return out;
@@ -63,7 +63,7 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
: "r" (newval), "0" (oldval)
: "memory");
return out;
-#elif defined(_AIX) && defined(__xlC__)
+#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
const long out = (*(volatile int*) ptr);
# if defined(__64BIT__)
__compare_and_swaplp(ptr, &oldval, newval);
diff --git a/Utilities/cmzlib/CMakeLists.txt b/Utilities/cmzlib/CMakeLists.txt
index 0be48f107..888c3ff77 100644
--- a/Utilities/cmzlib/CMakeLists.txt
+++ b/Utilities/cmzlib/CMakeLists.txt
@@ -2,7 +2,7 @@ PROJECT(CMZLIB)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmzstd/CMakeLists.txt b/Utilities/cmzstd/CMakeLists.txt
new file mode 100644
index 000000000..8ed04d8d1
--- /dev/null
+++ b/Utilities/cmzstd/CMakeLists.txt
@@ -0,0 +1,47 @@
+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)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+include_directories(lib lib/common)
+
+add_library(cmzstd STATIC
+ lib/common/entropy_common.c
+ lib/common/error_private.c
+ lib/common/fse_decompress.c
+ lib/common/pool.c
+ lib/common/threading.c
+ lib/common/xxhash.c
+ lib/common/zstd_common.c
+ lib/compress/fse_compress.c
+ lib/compress/hist.c
+ lib/compress/huf_compress.c
+ lib/compress/zstd_compress.c
+ lib/compress/zstd_double_fast.c
+ lib/compress/zstd_fast.c
+ lib/compress/zstd_lazy.c
+ lib/compress/zstd_ldm.c
+ lib/compress/zstdmt_compress.c
+ lib/compress/zstd_opt.c
+ lib/decompress/huf_decompress.c
+ lib/decompress/zstd_ddict.c
+ lib/decompress/zstd_decompress_block.c
+ lib/decompress/zstd_decompress.c
+ lib/deprecated/zbuff_common.c
+ lib/deprecated/zbuff_compress.c
+ lib/deprecated/zbuff_decompress.c
+ lib/dictBuilder/cover.c
+ lib/dictBuilder/divsufsort.c
+ lib/dictBuilder/fastcover.c
+ lib/dictBuilder/zdict.c
+ )
+
+# BMI2 instructions are not supported in older environments.
+set_property(TARGET cmzstd PROPERTY COMPILE_DEFINITIONS DYNAMIC_BMI2=0)
+
+install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmzstd)
diff --git a/Utilities/cmzstd/LICENSE b/Utilities/cmzstd/LICENSE
new file mode 100644
index 000000000..a793a8028
--- /dev/null
+++ b/Utilities/cmzstd/LICENSE
@@ -0,0 +1,30 @@
+BSD License
+
+For Zstandard software
+
+Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * 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.
+
+ * Neither the name Facebook 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
diff --git a/Utilities/cmzstd/README.md b/Utilities/cmzstd/README.md
new file mode 100644
index 000000000..4b6d19e7e
--- /dev/null
+++ b/Utilities/cmzstd/README.md
@@ -0,0 +1,167 @@
+<p align="center"><img src="https://raw.githubusercontent.com/facebook/zstd/dev/doc/images/zstd_logo86.png" alt="Zstandard"></p>
+
+__Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm,
+targeting real-time compression scenarios at zlib-level and better compression ratios.
+It's backed by a very fast entropy stage, provided by [Huff0 and FSE library](https://github.com/Cyan4973/FiniteStateEntropy).
+
+The project is provided as an open-source dual [BSD](LICENSE) and [GPLv2](COPYING) licensed **C** library,
+and a command line utility producing and decoding `.zst`, `.gz`, `.xz` and `.lz4` files.
+Should your project require another programming language,
+a list of known ports and bindings is provided on [Zstandard homepage](http://www.zstd.net/#other-languages).
+
+**Development branch status:**
+
+[![Build Status][travisDevBadge]][travisLink]
+[![Build status][AppveyorDevBadge]][AppveyorLink]
+[![Build status][CircleDevBadge]][CircleLink]
+
+[travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite"
+[travisLink]: https://travis-ci.org/facebook/zstd
+[AppveyorDevBadge]: https://ci.appveyor.com/api/projects/status/xt38wbdxjk5mrbem/branch/dev?svg=true "Windows test suite"
+[AppveyorLink]: https://ci.appveyor.com/project/YannCollet/zstd-p0yf0
+[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite"
+[CircleLink]: https://circleci.com/gh/facebook/zstd
+
+## Benchmarks
+
+For reference, several fast compression algorithms were tested and compared
+on a server running Linux Debian (`Linux version 4.14.0-3-amd64`),
+with a Core i7-6700K CPU @ 4.0GHz,
+using [lzbench], an open-source in-memory benchmark by @inikep
+compiled with [gcc] 7.3.0,
+on the [Silesia compression corpus].
+
+[lzbench]: https://github.com/inikep/lzbench
+[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
+[gcc]: https://gcc.gnu.org/
+
+| Compressor name | Ratio | Compression| Decompress.|
+| --------------- | ------| -----------| ---------- |
+| **zstd 1.3.4 -1** | 2.877 | 470 MB/s | 1380 MB/s |
+| zlib 1.2.11 -1 | 2.743 | 110 MB/s | 400 MB/s |
+| brotli 1.0.2 -0 | 2.701 | 410 MB/s | 430 MB/s |
+| quicklz 1.5.0 -1 | 2.238 | 550 MB/s | 710 MB/s |
+| lzo1x 2.09 -1 | 2.108 | 650 MB/s | 830 MB/s |
+| lz4 1.8.1 | 2.101 | 750 MB/s | 3700 MB/s |
+| snappy 1.1.4 | 2.091 | 530 MB/s | 1800 MB/s |
+| lzf 3.6 -1 | 2.077 | 400 MB/s | 860 MB/s |
+
+[zlib]: http://www.zlib.net/
+[LZ4]: http://www.lz4.org/
+
+Zstd can also offer stronger compression ratios at the cost of compression speed.
+Speed vs Compression trade-off is configurable by small increments.
+Decompression speed is preserved and remains roughly the same at all settings,
+a property shared by most LZ compression algorithms, such as [zlib] or lzma.
+
+The following tests were run
+on a server running Linux Debian (`Linux version 4.14.0-3-amd64`)
+with a Core i7-6700K CPU @ 4.0GHz,
+using [lzbench], an open-source in-memory benchmark by @inikep
+compiled with [gcc] 7.3.0,
+on the [Silesia compression corpus].
+
+Compression Speed vs Ratio | Decompression Speed
+---------------------------|--------------------
+![Compression Speed vs Ratio](doc/images/CSpeed2.png "Compression Speed vs Ratio") | ![Decompression Speed](doc/images/DSpeed3.png "Decompression Speed")
+
+A few other algorithms can produce higher compression ratios at slower speeds, falling outside of the graph.
+For a larger picture including slow modes, [click on this link](doc/images/DCspeed5.png).
+
+
+## The case for Small Data compression
+
+Previous charts provide results applicable to typical file and stream scenarios (several MB). Small data comes with different perspectives.
+
+The smaller the amount of data to compress, the more difficult it is to compress. This problem is common to all compression algorithms, and reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new data set, there is no "past" to build upon.
+
+To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data.
+Training Zstandard is achieved by providing it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression.
+Using this dictionary, the compression ratio achievable on small data improves dramatically.
+
+The following example uses the `github-users` [sample set](https://github.com/facebook/zstd/releases/tag/v1.1.3), created from [github public API](https://developer.github.com/v3/users/#get-all-users).
+It consists of roughly 10K records weighing about 1KB each.
+
+Compression Ratio | Compression Speed | Decompression Speed
+------------------|-------------------|--------------------
+![Compression Ratio](doc/images/dict-cr.png "Compression Ratio") | ![Compression Speed](doc/images/dict-cs.png "Compression Speed") | ![Decompression Speed](doc/images/dict-ds.png "Decompression Speed")
+
+
+These compression gains are achieved while simultaneously providing _faster_ compression and decompression speeds.
+
+Training works if there is some correlation in a family of small data samples. The more data-specific a dictionary is, the more efficient it is (there is no _universal dictionary_).
+Hence, deploying one dictionary per type of data will provide the greatest benefits.
+Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will gradually use previously decoded content to better compress the rest of the file.
+
+### Dictionary compression How To:
+
+1. Create the dictionary
+
+ `zstd --train FullPathToTrainingSet/* -o dictionaryName`
+
+2. Compress with dictionary
+
+ `zstd -D dictionaryName FILE`
+
+3. Decompress with dictionary
+
+ `zstd -D dictionaryName --decompress FILE.zst`
+
+
+## Build instructions
+
+### Makefile
+
+If your system is compatible with standard `make` (or `gmake`),
+invoking `make` in root directory will generate `zstd` cli in root directory.
+
+Other available options include:
+- `make install` : create and install zstd cli, library and man pages
+- `make check` : create and run `zstd`, tests its behavior on local platform
+
+### cmake
+
+A `cmake` project generator is provided within `build/cmake`.
+It can generate Makefiles or other build scripts
+to create `zstd` binary, and `libzstd` dynamic and static libraries.
+
+By default, `CMAKE_BUILD_TYPE` is set to `Release`.
+
+### Meson
+
+A Meson project is provided within [`build/meson`](build/meson). Follow
+build instructions in that directory.
+
+You can also take a look at [`.travis.yml`](.travis.yml) file for an
+example about how Meson is used to build this project.
+
+Note that default build type is **release**.
+
+### Visual Studio (Windows)
+
+Going into `build` directory, you will find additional possibilities:
+- Projects for Visual Studio 2005, 2008 and 2010.
+ + VS2010 project is compatible with VS2012, VS2013, VS2015 and VS2017.
+- Automated build scripts for Visual compiler by [@KrzysFR](https://github.com/KrzysFR), in `build/VS_scripts`,
+ which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.
+
+### Buck
+
+You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
+The output binary will be in `buck-out/gen/programs/`.
+
+## Status
+
+Zstandard is currently deployed within Facebook. It is used continuously to compress large amounts of data in multiple formats and use cases.
+Zstandard is considered safe for production environments.
+
+## License
+
+Zstandard is dual-licensed under [BSD](LICENSE) and [GPLv2](COPYING).
+
+## Contributing
+
+The "dev" branch is the one where all contributions are merged before reaching "master".
+If you plan to propose a patch, please commit into the "dev" branch, or its own feature branch.
+Direct commit to "master" are not permitted.
+For more information, please read [CONTRIBUTING](CONTRIBUTING.md).
diff --git a/Utilities/cmzstd/lib/common/bitstream.h b/Utilities/cmzstd/lib/common/bitstream.h
new file mode 100644
index 000000000..d955bd677
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/bitstream.h
@@ -0,0 +1,455 @@
+/* ******************************************************************
+ bitstream
+ Part of FSE library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+#ifndef BITSTREAM_H_MODULE
+#define BITSTREAM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+* This API consists of small unitary functions, which must be inlined for best performance.
+* Since link-time-optimization is not available for all compilers,
+* these functions are defined into a .h to be included.
+*/
+
+/*-****************************************
+* Dependencies
+******************************************/
+#include "mem.h" /* unaligned access routines */
+#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
+#include "error_private.h" /* error codes and messages */
+
+
+/*=========================================
+* Target specific
+=========================================*/
+#if defined(__BMI__) && defined(__GNUC__)
+# include <immintrin.h> /* support for bextr (experimental) */
+#endif
+
+#define STREAM_ACCUMULATOR_MIN_32 25
+#define STREAM_ACCUMULATOR_MIN_64 57
+#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
+
+
+/*-******************************************
+* bitStream encoding API (write forward)
+********************************************/
+/* bitStream can mix input from multiple sources.
+ * A critical property of these streams is that they encode and decode in **reverse** direction.
+ * So the first bit sequence you add will be the last to be read, like a LIFO stack.
+ */
+typedef struct {
+ size_t bitContainer;
+ unsigned bitPos;
+ char* startPtr;
+ char* ptr;
+ char* endPtr;
+} BIT_CStream_t;
+
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
+
+/* Start with initCStream, providing the size of buffer to write into.
+* bitStream will never write outside of this buffer.
+* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
+*
+* bits are first added to a local register.
+* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
+* Writing data into memory is an explicit operation, performed by the flushBits function.
+* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
+* After a flushBits, a maximum of 7 bits might still be stored into local register.
+*
+* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
+*
+* Last operation is to close the bitStream.
+* The function returns the final size of CStream in bytes.
+* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
+*/
+
+
+/*-********************************************
+* bitStream decoding API (read backward)
+**********************************************/
+typedef struct {
+ size_t bitContainer;
+ unsigned bitsConsumed;
+ const char* ptr;
+ const char* start;
+ const char* limitPtr;
+} BIT_DStream_t;
+
+typedef enum { BIT_DStream_unfinished = 0,
+ BIT_DStream_endOfBuffer = 1,
+ BIT_DStream_completed = 2,
+ BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
+ /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
+
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
+
+
+/* Start by invoking BIT_initDStream().
+* A chunk of the bitStream is then stored into a local register.
+* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+* You can then retrieve bitFields stored into the local register, **in reverse order**.
+* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
+* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
+* Otherwise, it can be less than that, so proceed accordingly.
+* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
+*/
+
+
+/*-****************************************
+* unsafe API
+******************************************/
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
+
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
+/* unsafe version; does not check buffer overflow */
+
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
+/* faster, but works only if nbBits >= 1 */
+
+
+
+/*-**************************************************************
+* Internal functions
+****************************************************************/
+MEM_STATIC unsigned BIT_highbit32 (U32 val)
+{
+ assert(val != 0);
+ {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ _BitScanReverse ( &r, val );
+ return (unsigned) r;
+# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
+ return 31 - __builtin_clz (val);
+# else /* Software version */
+ static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
+ 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7,
+ 19, 27, 23, 6, 26, 5, 4, 31 };
+ U32 v = val;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
+# endif
+ }
+}
+
+/*===== Local Constants =====*/
+static const unsigned BIT_mask[] = {
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
+ 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
+ 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
+ 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
+#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
+
+/*-**************************************************************
+* bitStream encoding
+****************************************************************/
+/*! BIT_initCStream() :
+ * `dstCapacity` must be > sizeof(size_t)
+ * @return : 0 if success,
+ * otherwise an error code (can be tested using ERR_isError()) */
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
+ void* startPtr, size_t dstCapacity)
+{
+ bitC->bitContainer = 0;
+ bitC->bitPos = 0;
+ bitC->startPtr = (char*)startPtr;
+ bitC->ptr = bitC->startPtr;
+ bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
+ if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
+ return 0;
+}
+
+/*! BIT_addBits() :
+ * can add up to 31 bits into `bitC`.
+ * Note : does not check for register overflow ! */
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
+ assert(nbBits < BIT_MASK_SIZE);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_addBitsFast() :
+ * works only if `value` is _clean_,
+ * meaning all high bits above nbBits are 0 */
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ assert((value>>nbBits) == 0);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= value << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_flushBitsFast() :
+ * assumption : bitContainer has not overflowed
+ * unsafe version; does not check buffer overflow */
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ assert(bitC->ptr <= bitC->endPtr);
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_flushBits() :
+ * assumption : bitContainer has not overflowed
+ * safe version; check for buffer overflow, and prevents it.
+ * note : does not signal buffer overflow.
+ * overflow will be revealed later on using BIT_closeCStream() */
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_closeCStream() :
+ * @return : size of CStream, in bytes,
+ * or 0 if it could not fit into dstBuffer */
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
+{
+ BIT_addBitsFast(bitC, 1, 1); /* endMark */
+ BIT_flushBits(bitC);
+ if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
+ return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
+}
+
+
+/*-********************************************************
+* bitStream decoding
+**********************************************************/
+/*! BIT_initDStream() :
+ * Initialize a BIT_DStream_t.
+ * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
+ * `srcSize` must be the *exact* size of the bitStream, in bytes.
+ * @return : size of stream (== srcSize), or an errorCode if a problem is detected
+ */
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
+{
+ if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+
+ bitD->start = (const char*)srcBuffer;
+ bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
+
+ if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
+ bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
+ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
+ } else {
+ bitD->ptr = bitD->start;
+ bitD->bitContainer = *(const BYTE*)(bitD->start);
+ switch(srcSize)
+ {
+ case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
+ /* fall-through */
+
+ case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
+ /* fall-through */
+
+ case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
+ /* fall-through */
+
+ case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
+ /* fall-through */
+
+ case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
+ /* fall-through */
+
+ case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
+ /* fall-through */
+
+ default: break;
+ }
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
+ if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
+ }
+ bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
+ }
+
+ return srcSize;
+}
+
+MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
+{
+ return bitContainer >> start;
+}
+
+MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
+{
+ U32 const regMask = sizeof(bitContainer)*8 - 1;
+ /* if start > regMask, bitstream is corrupted, and result is undefined */
+ assert(nbBits < BIT_MASK_SIZE);
+ return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
+}
+
+MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
+{
+ assert(nbBits < BIT_MASK_SIZE);
+ return bitContainer & BIT_mask[nbBits];
+}
+
+/*! BIT_lookBits() :
+ * Provides next n bits from local register.
+ * local register is not modified.
+ * On 32-bits, maxNbBits==24.
+ * On 64-bits, maxNbBits==56.
+ * @return : value extracted */
+MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+{
+ /* arbitrate between double-shift and shift+mask */
+#if 1
+ /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
+ * bitstream is likely corrupted, and result is undefined */
+ return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
+#else
+ /* this code path is slower on my os-x laptop */
+ U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+ return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
+#endif
+}
+
+/*! BIT_lookBitsFast() :
+ * unsafe version; only works if nbBits >= 1 */
+MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
+{
+ U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+ assert(nbBits >= 1);
+ return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
+}
+
+MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
+{
+ bitD->bitsConsumed += nbBits;
+}
+
+/*! BIT_readBits() :
+ * Read (consume) next n bits from local register and update.
+ * Pay attention to not read more than nbBits contained into local register.
+ * @return : extracted value. */
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
+{
+ size_t const value = BIT_lookBits(bitD, nbBits);
+ BIT_skipBits(bitD, nbBits);
+ return value;
+}
+
+/*! BIT_readBitsFast() :
+ * unsafe version; only works only if nbBits >= 1 */
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
+{
+ size_t const value = BIT_lookBitsFast(bitD, nbBits);
+ assert(nbBits >= 1);
+ BIT_skipBits(bitD, nbBits);
+ return value;
+}
+
+/*! BIT_reloadDStream() :
+ * Refill `bitD` from buffer previously set in BIT_initDStream() .
+ * This function is safe, it guarantees it will not read beyond src buffer.
+ * @return : status of `BIT_DStream_t` internal register.
+ * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
+{
+ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
+ return BIT_DStream_overflow;
+
+ if (bitD->ptr >= bitD->limitPtr) {
+ bitD->ptr -= bitD->bitsConsumed >> 3;
+ bitD->bitsConsumed &= 7;
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ return BIT_DStream_unfinished;
+ }
+ if (bitD->ptr == bitD->start) {
+ if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
+ return BIT_DStream_completed;
+ }
+ /* start < ptr < limitPtr */
+ { U32 nbBytes = bitD->bitsConsumed >> 3;
+ BIT_DStream_status result = BIT_DStream_unfinished;
+ if (bitD->ptr - nbBytes < bitD->start) {
+ nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
+ result = BIT_DStream_endOfBuffer;
+ }
+ bitD->ptr -= nbBytes;
+ bitD->bitsConsumed -= nbBytes*8;
+ bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
+ return result;
+ }
+}
+
+/*! BIT_endOfDStream() :
+ * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
+ */
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
+{
+ return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* BITSTREAM_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/compiler.h b/Utilities/cmzstd/lib/common/compiler.h
new file mode 100644
index 000000000..7f561282c
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/compiler.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPILER_H
+#define ZSTD_COMPILER_H
+
+/*-*******************************************************
+* Compiler specifics
+*********************************************************/
+/* force inlining */
+
+#if !defined(ZSTD_NO_INLINE)
+#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define INLINE_KEYWORD inline
+#else
+# define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__)
+# define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define FORCE_INLINE_ATTR __forceinline
+#else
+# define FORCE_INLINE_ATTR
+#endif
+
+#else
+
+#define INLINE_KEYWORD
+#define FORCE_INLINE_ATTR
+
+#endif
+
+/**
+ * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
+ * parameters. They must be inlined for the compiler to elimininate the constant
+ * branches.
+ */
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+/**
+ * HINT_INLINE is used to help the compiler generate better code. It is *not*
+ * used for "templates", so it can be tweaked based on the compilers
+ * performance.
+ *
+ * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
+ * always_inline attribute.
+ *
+ * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
+ * attribute.
+ */
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
+# define HINT_INLINE static INLINE_KEYWORD
+#else
+# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
+#endif
+
+/* force no inlining */
+#ifdef _MSC_VER
+# define FORCE_NOINLINE static __declspec(noinline)
+#else
+# ifdef __GNUC__
+# define FORCE_NOINLINE static __attribute__((__noinline__))
+# else
+# define FORCE_NOINLINE static
+# endif
+#endif
+
+/* target attribute */
+#ifndef __has_attribute
+ #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+#if defined(__GNUC__)
+# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
+#else
+# define TARGET_ATTRIBUTE(target)
+#endif
+
+/* Enable runtime BMI2 dispatch based on the CPU.
+ * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
+ */
+#ifndef DYNAMIC_BMI2
+ #if ((defined(__clang__) && __has_attribute(__target__)) \
+ || (defined(__GNUC__) \
+ && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
+ && (defined(__x86_64__) || defined(_M_X86)) \
+ && !defined(__BMI2__)
+ # define DYNAMIC_BMI2 1
+ #else
+ # define DYNAMIC_BMI2 0
+ #endif
+#endif
+
+/* prefetch
+ * can be disabled, by declaring NO_PREFETCH build macro */
+#if defined(NO_PREFETCH)
+# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
+# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
+#else
+# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
+# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
+# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
+# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
+# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
+# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
+# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
+# else
+# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
+# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
+# endif
+#endif /* NO_PREFETCH */
+
+#define CACHELINE_SIZE 64
+
+#define PREFETCH_AREA(p, s) { \
+ const char* const _ptr = (const char*)(p); \
+ size_t const _size = (size_t)(s); \
+ size_t _pos; \
+ for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
+ PREFETCH_L2(_ptr + _pos); \
+ } \
+}
+
+/* disable warnings */
+#ifdef _MSC_VER /* Visual Studio */
+# include <intrin.h> /* For Visual 2005 */
+# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
+# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
+# pragma warning(disable : 4324) /* disable: C4324: padded structure */
+#endif
+
+#endif /* ZSTD_COMPILER_H */
diff --git a/Utilities/cmzstd/lib/common/cpu.h b/Utilities/cmzstd/lib/common/cpu.h
new file mode 100644
index 000000000..5f0923fc9
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/cpu.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMMON_CPU_H
+#define ZSTD_COMMON_CPU_H
+
+/**
+ * Implementation taken from folly/CpuId.h
+ * https://github.com/facebook/folly/blob/master/folly/CpuId.h
+ */
+
+#include <string.h>
+
+#include "mem.h"
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+typedef struct {
+ U32 f1c;
+ U32 f1d;
+ U32 f7b;
+ U32 f7c;
+} ZSTD_cpuid_t;
+
+MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
+ U32 f1c = 0;
+ U32 f1d = 0;
+ U32 f7b = 0;
+ U32 f7c = 0;
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+ int reg[4];
+ __cpuid((int*)reg, 0);
+ {
+ int const n = reg[0];
+ if (n >= 1) {
+ __cpuid((int*)reg, 1);
+ f1c = (U32)reg[2];
+ f1d = (U32)reg[3];
+ }
+ if (n >= 7) {
+ __cpuidex((int*)reg, 7, 0);
+ f7b = (U32)reg[1];
+ f7c = (U32)reg[2];
+ }
+ }
+#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
+ /* The following block like the normal cpuid branch below, but gcc
+ * reserves ebx for use of its pic register so we must specially
+ * handle the save and restore to avoid clobbering the register
+ */
+ U32 n;
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "popl %%ebx\n\t"
+ : "=a"(n)
+ : "a"(0)
+ : "ecx", "edx");
+ if (n >= 1) {
+ U32 f1a;
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "popl %%ebx\n\t"
+ : "=a"(f1a), "=c"(f1c), "=d"(f1d)
+ : "a"(1));
+ }
+ if (n >= 7) {
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "movl %%ebx, %%eax\n\t"
+ "popl %%ebx"
+ : "=a"(f7b), "=c"(f7c)
+ : "a"(7), "c"(0)
+ : "edx");
+ }
+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
+ U32 n;
+ __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
+ if (n >= 1) {
+ U32 f1a;
+ __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
+ }
+ if (n >= 7) {
+ U32 f7a;
+ __asm__("cpuid"
+ : "=a"(f7a), "=b"(f7b), "=c"(f7c)
+ : "a"(7), "c"(0)
+ : "edx");
+ }
+#endif
+ {
+ ZSTD_cpuid_t cpuid;
+ cpuid.f1c = f1c;
+ cpuid.f1d = f1d;
+ cpuid.f7b = f7b;
+ cpuid.f7c = f7c;
+ return cpuid;
+ }
+}
+
+#define X(name, r, bit) \
+ MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
+ return ((cpuid.r) & (1U << bit)) != 0; \
+ }
+
+/* cpuid(1): Processor Info and Feature Bits. */
+#define C(name, bit) X(name, f1c, bit)
+ C(sse3, 0)
+ C(pclmuldq, 1)
+ C(dtes64, 2)
+ C(monitor, 3)
+ C(dscpl, 4)
+ C(vmx, 5)
+ C(smx, 6)
+ C(eist, 7)
+ C(tm2, 8)
+ C(ssse3, 9)
+ C(cnxtid, 10)
+ C(fma, 12)
+ C(cx16, 13)
+ C(xtpr, 14)
+ C(pdcm, 15)
+ C(pcid, 17)
+ C(dca, 18)
+ C(sse41, 19)
+ C(sse42, 20)
+ C(x2apic, 21)
+ C(movbe, 22)
+ C(popcnt, 23)
+ C(tscdeadline, 24)
+ C(aes, 25)
+ C(xsave, 26)
+ C(osxsave, 27)
+ C(avx, 28)
+ C(f16c, 29)
+ C(rdrand, 30)
+#undef C
+#define D(name, bit) X(name, f1d, bit)
+ D(fpu, 0)
+ D(vme, 1)
+ D(de, 2)
+ D(pse, 3)
+ D(tsc, 4)
+ D(msr, 5)
+ D(pae, 6)
+ D(mce, 7)
+ D(cx8, 8)
+ D(apic, 9)
+ D(sep, 11)
+ D(mtrr, 12)
+ D(pge, 13)
+ D(mca, 14)
+ D(cmov, 15)
+ D(pat, 16)
+ D(pse36, 17)
+ D(psn, 18)
+ D(clfsh, 19)
+ D(ds, 21)
+ D(acpi, 22)
+ D(mmx, 23)
+ D(fxsr, 24)
+ D(sse, 25)
+ D(sse2, 26)
+ D(ss, 27)
+ D(htt, 28)
+ D(tm, 29)
+ D(pbe, 31)
+#undef D
+
+/* cpuid(7): Extended Features. */
+#define B(name, bit) X(name, f7b, bit)
+ B(bmi1, 3)
+ B(hle, 4)
+ B(avx2, 5)
+ B(smep, 7)
+ B(bmi2, 8)
+ B(erms, 9)
+ B(invpcid, 10)
+ B(rtm, 11)
+ B(mpx, 14)
+ B(avx512f, 16)
+ B(avx512dq, 17)
+ B(rdseed, 18)
+ B(adx, 19)
+ B(smap, 20)
+ B(avx512ifma, 21)
+ B(pcommit, 22)
+ B(clflushopt, 23)
+ B(clwb, 24)
+ B(avx512pf, 26)
+ B(avx512er, 27)
+ B(avx512cd, 28)
+ B(sha, 29)
+ B(avx512bw, 30)
+ B(avx512vl, 31)
+#undef B
+#define C(name, bit) X(name, f7c, bit)
+ C(prefetchwt1, 0)
+ C(avx512vbmi, 1)
+#undef C
+
+#undef X
+
+#endif /* ZSTD_COMMON_CPU_H */
diff --git a/Utilities/cmzstd/lib/common/debug.c b/Utilities/cmzstd/lib/common/debug.c
new file mode 100644
index 000000000..3ebdd1cb1
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/debug.c
@@ -0,0 +1,44 @@
+/* ******************************************************************
+ debug
+ Part of FSE library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+
+/*
+ * This module only hosts one global variable
+ * which can be used to dynamically influence the verbosity of traces,
+ * such as DEBUGLOG and RAWLOG
+ */
+
+#include "debug.h"
+
+int g_debuglevel = DEBUGLEVEL;
diff --git a/Utilities/cmzstd/lib/common/debug.h b/Utilities/cmzstd/lib/common/debug.h
new file mode 100644
index 000000000..b4fc89d49
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/debug.h
@@ -0,0 +1,134 @@
+/* ******************************************************************
+ debug
+ Part of FSE library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+
+/*
+ * The purpose of this header is to enable debug functions.
+ * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
+ * and DEBUG_STATIC_ASSERT() for compile-time.
+ *
+ * By default, DEBUGLEVEL==0, which means run-time debug is disabled.
+ *
+ * Level 1 enables assert() only.
+ * Starting level 2, traces can be generated and pushed to stderr.
+ * The higher the level, the more verbose the traces.
+ *
+ * It's possible to dynamically adjust level using variable g_debug_level,
+ * which is only declared if DEBUGLEVEL>=2,
+ * and is a global variable, not multi-thread protected (use with care)
+ */
+
+#ifndef DEBUG_H_12987983217
+#define DEBUG_H_12987983217
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* static assert is triggered at compile time, leaving no runtime artefact.
+ * static assert only works with compile-time constants.
+ * Also, this variant can only be used inside a function. */
+#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
+
+
+/* DEBUGLEVEL is expected to be defined externally,
+ * typically through compiler command line.
+ * Value must be a number. */
+#ifndef DEBUGLEVEL
+# define DEBUGLEVEL 0
+#endif
+
+
+/* DEBUGFILE can be defined externally,
+ * typically through compiler command line.
+ * note : currently useless.
+ * Value must be stderr or stdout */
+#ifndef DEBUGFILE
+# define DEBUGFILE stderr
+#endif
+
+
+/* recommended values for DEBUGLEVEL :
+ * 0 : release mode, no debug, all run-time checks disabled
+ * 1 : enables assert() only, no display
+ * 2 : reserved, for currently active debug path
+ * 3 : events once per object lifetime (CCtx, CDict, etc.)
+ * 4 : events once per frame
+ * 5 : events once per block
+ * 6 : events once per sequence (verbose)
+ * 7+: events at every position (*very* verbose)
+ *
+ * It's generally inconvenient to output traces > 5.
+ * In which case, it's possible to selectively trigger high verbosity levels
+ * by modifying g_debug_level.
+ */
+
+#if (DEBUGLEVEL>=1)
+# include <assert.h>
+#else
+# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
+# define assert(condition) ((void)0) /* disable assert (default) */
+# endif
+#endif
+
+#if (DEBUGLEVEL>=2)
+# include <stdio.h>
+extern int g_debuglevel; /* the variable is only declared,
+ it actually lives in debug.c,
+ and is shared by the whole process.
+ It's not thread-safe.
+ It's useful when enabling very verbose levels
+ on selective conditions (such as position in src) */
+
+# define RAWLOG(l, ...) { \
+ if (l<=g_debuglevel) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } }
+# define DEBUGLOG(l, ...) { \
+ if (l<=g_debuglevel) { \
+ fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
+ fprintf(stderr, " \n"); \
+ } }
+#else
+# define RAWLOG(l, ...) {} /* disabled */
+# define DEBUGLOG(l, ...) {} /* disabled */
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* DEBUG_H_12987983217 */
diff --git a/Utilities/cmzstd/lib/common/entropy_common.c b/Utilities/cmzstd/lib/common/entropy_common.c
new file mode 100644
index 000000000..b12944e1d
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/entropy_common.c
@@ -0,0 +1,236 @@
+/*
+ Common functions of New Generation Entropy library
+ Copyright (C) 2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+*************************************************************************** */
+
+/* *************************************
+* Dependencies
+***************************************/
+#include "mem.h"
+#include "error_private.h" /* ERR_*, ERROR */
+#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
+#include "huf.h"
+
+
+/*=== Version ===*/
+unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
+
+
+/*=== Error Management ===*/
+unsigned FSE_isError(size_t code) { return ERR_isError(code); }
+const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+unsigned HUF_isError(size_t code) { return ERR_isError(code); }
+const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+
+/*-**************************************************************
+* FSE NCount encoding-decoding
+****************************************************************/
+size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+ const void* headerBuffer, size_t hbSize)
+{
+ const BYTE* const istart = (const BYTE*) headerBuffer;
+ const BYTE* const iend = istart + hbSize;
+ const BYTE* ip = istart;
+ int nbBits;
+ int remaining;
+ int threshold;
+ U32 bitStream;
+ int bitCount;
+ unsigned charnum = 0;
+ int previous0 = 0;
+
+ if (hbSize < 4) {
+ /* This function only works when hbSize >= 4 */
+ char buffer[4];
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, headerBuffer, hbSize);
+ { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
+ buffer, sizeof(buffer));
+ if (FSE_isError(countSize)) return countSize;
+ if (countSize > hbSize) return ERROR(corruption_detected);
+ return countSize;
+ } }
+ assert(hbSize >= 4);
+
+ /* init */
+ memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
+ bitStream = MEM_readLE32(ip);
+ nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
+ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
+ bitStream >>= 4;
+ bitCount = 4;
+ *tableLogPtr = nbBits;
+ remaining = (1<<nbBits)+1;
+ threshold = 1<<nbBits;
+ nbBits++;
+
+ while ((remaining>1) & (charnum<=*maxSVPtr)) {
+ if (previous0) {
+ unsigned n0 = charnum;
+ while ((bitStream & 0xFFFF) == 0xFFFF) {
+ n0 += 24;
+ if (ip < iend-5) {
+ ip += 2;
+ bitStream = MEM_readLE32(ip) >> bitCount;
+ } else {
+ bitStream >>= 16;
+ bitCount += 16;
+ } }
+ while ((bitStream & 3) == 3) {
+ n0 += 3;
+ bitStream >>= 2;
+ bitCount += 2;
+ }
+ n0 += bitStream & 3;
+ bitCount += 2;
+ if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
+ while (charnum < n0) normalizedCounter[charnum++] = 0;
+ if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+ assert((bitCount >> 3) <= 3); /* For first condition to work */
+ ip += bitCount>>3;
+ bitCount &= 7;
+ bitStream = MEM_readLE32(ip) >> bitCount;
+ } else {
+ bitStream >>= 2;
+ } }
+ { int const max = (2*threshold-1) - remaining;
+ int count;
+
+ if ((bitStream & (threshold-1)) < (U32)max) {
+ count = bitStream & (threshold-1);
+ bitCount += nbBits-1;
+ } else {
+ count = bitStream & (2*threshold-1);
+ if (count >= threshold) count -= max;
+ bitCount += nbBits;
+ }
+
+ count--; /* extra accuracy */
+ remaining -= count < 0 ? -count : count; /* -1 means +1 */
+ normalizedCounter[charnum++] = (short)count;
+ previous0 = !count;
+ while (remaining < threshold) {
+ nbBits--;
+ threshold >>= 1;
+ }
+
+ if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+ ip += bitCount>>3;
+ bitCount &= 7;
+ } else {
+ bitCount -= (int)(8 * (iend - 4 - ip));
+ ip = iend - 4;
+ }
+ bitStream = MEM_readLE32(ip) >> (bitCount & 31);
+ } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
+ if (remaining != 1) return ERROR(corruption_detected);
+ if (bitCount > 32) return ERROR(corruption_detected);
+ *maxSVPtr = charnum-1;
+
+ ip += (bitCount+7)>>3;
+ return ip-istart;
+}
+
+
+/*! HUF_readStats() :
+ Read compact Huffman tree, saved by HUF_writeCTable().
+ `huffWeight` is destination buffer.
+ `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
+ @return : size read from `src` , or an error Code .
+ Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
+*/
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+ U32* nbSymbolsPtr, U32* tableLogPtr,
+ const void* src, size_t srcSize)
+{
+ U32 weightTotal;
+ const BYTE* ip = (const BYTE*) src;
+ size_t iSize;
+ size_t oSize;
+
+ if (!srcSize) return ERROR(srcSize_wrong);
+ iSize = ip[0];
+ /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
+
+ if (iSize >= 128) { /* special header */
+ oSize = iSize - 127;
+ iSize = ((oSize+1)/2);
+ if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+ if (oSize >= hwSize) return ERROR(corruption_detected);
+ ip += 1;
+ { U32 n;
+ for (n=0; n<oSize; n+=2) {
+ huffWeight[n] = ip[n/2] >> 4;
+ huffWeight[n+1] = ip[n/2] & 15;
+ } } }
+ else { /* header compressed with FSE (normal case) */
+ FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
+ if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+ oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
+ if (FSE_isError(oSize)) return oSize;
+ }
+
+ /* collect weight stats */
+ memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
+ weightTotal = 0;
+ { U32 n; for (n=0; n<oSize; n++) {
+ if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ rankStats[huffWeight[n]]++;
+ weightTotal += (1 << huffWeight[n]) >> 1;
+ } }
+ if (weightTotal == 0) return ERROR(corruption_detected);
+
+ /* get last non-null symbol weight (implied, total must be 2^n) */
+ { U32 const tableLog = BIT_highbit32(weightTotal) + 1;
+ if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ *tableLogPtr = tableLog;
+ /* determine last weight */
+ { U32 const total = 1 << tableLog;
+ U32 const rest = total - weightTotal;
+ U32 const verif = 1 << BIT_highbit32(rest);
+ U32 const lastWeight = BIT_highbit32(rest) + 1;
+ if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
+ huffWeight[oSize] = (BYTE)lastWeight;
+ rankStats[lastWeight]++;
+ } }
+
+ /* check tree construction validity */
+ if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
+
+ /* results */
+ *nbSymbolsPtr = (U32)(oSize+1);
+ return iSize+1;
+}
diff --git a/Utilities/cmzstd/lib/common/error_private.c b/Utilities/cmzstd/lib/common/error_private.c
new file mode 100644
index 000000000..7c1bb67a2
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/error_private.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* The purpose of this file is to have a single list of error strings embedded in binary */
+
+#include "error_private.h"
+
+const char* ERR_getErrorString(ERR_enum code)
+{
+#ifdef ZSTD_STRIP_ERROR_STRINGS
+ (void)code;
+ return "Error strings stripped";
+#else
+ static const char* const notErrorCode = "Unspecified error code";
+ switch( code )
+ {
+ case PREFIX(no_error): return "No error detected";
+ case PREFIX(GENERIC): return "Error (generic)";
+ case PREFIX(prefix_unknown): return "Unknown frame descriptor";
+ case PREFIX(version_unsupported): return "Version not supported";
+ case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
+ case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
+ case PREFIX(corruption_detected): return "Corrupted block detected";
+ case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
+ case PREFIX(parameter_unsupported): return "Unsupported parameter";
+ case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
+ case PREFIX(init_missing): return "Context should be init first";
+ case PREFIX(memory_allocation): return "Allocation error : not enough memory";
+ case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
+ case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
+ case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
+ case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
+ case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
+ case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
+ case PREFIX(dictionary_wrong): return "Dictionary mismatch";
+ case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
+ case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
+ case PREFIX(srcSize_wrong): return "Src size is incorrect";
+ case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
+ /* following error codes are not stable and may be removed or changed in a future version */
+ case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
+ case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
+ case PREFIX(maxCode):
+ default: return notErrorCode;
+ }
+#endif
+}
diff --git a/Utilities/cmzstd/lib/common/error_private.h b/Utilities/cmzstd/lib/common/error_private.h
new file mode 100644
index 000000000..0d2fa7e34
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/error_private.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* Note : this module is expected to remain private, do not expose it */
+
+#ifndef ERROR_H_MODULE
+#define ERROR_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t */
+#include "zstd_errors.h" /* enum list */
+
+
+/* ****************************************
+* Compiler-specific
+******************************************/
+#if defined(__GNUC__)
+# define ERR_STATIC static __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define ERR_STATIC static inline
+#elif defined(_MSC_VER)
+# define ERR_STATIC static __inline
+#else
+# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+
+/*-****************************************
+* Customization (error_public.h)
+******************************************/
+typedef ZSTD_ErrorCode ERR_enum;
+#define PREFIX(name) ZSTD_error_##name
+
+
+/*-****************************************
+* Error codes handling
+******************************************/
+#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
+#define ERROR(name) ZSTD_ERROR(name)
+#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
+
+ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
+
+ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
+
+
+/*-****************************************
+* Error Strings
+******************************************/
+
+const char* ERR_getErrorString(ERR_enum code); /* error_private.c */
+
+ERR_STATIC const char* ERR_getErrorName(size_t code)
+{
+ return ERR_getErrorString(ERR_getErrorCode(code));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ERROR_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/fse.h b/Utilities/cmzstd/lib/common/fse.h
new file mode 100644
index 000000000..f72c519b2
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/fse.h
@@ -0,0 +1,708 @@
+/* ******************************************************************
+ FSE : Finite State Entropy codec
+ Public Prototypes declaration
+ Copyright (C) 2013-2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef FSE_H
+#define FSE_H
+
+
+/*-*****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t, ptrdiff_t */
+
+
+/*-*****************************************
+* FSE_PUBLIC_API : control library symbols visibility
+******************************************/
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+# define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
+# define FSE_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define FSE_PUBLIC_API
+#endif
+
+/*------ Version ------*/
+#define FSE_VERSION_MAJOR 0
+#define FSE_VERSION_MINOR 9
+#define FSE_VERSION_RELEASE 0
+
+#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
+#define FSE_QUOTE(str) #str
+#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
+#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
+
+#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
+FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
+
+
+/*-****************************************
+* FSE simple functions
+******************************************/
+/*! FSE_compress() :
+ Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
+ 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
+ @return : size of compressed data (<= dstCapacity).
+ Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+ if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
+ if FSE_isError(return), compression failed (more details using FSE_getErrorName())
+*/
+FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+/*! FSE_decompress():
+ Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
+ into already allocated destination buffer 'dst', of size 'dstCapacity'.
+ @return : size of regenerated data (<= maxDstSize),
+ or an error code, which can be tested using FSE_isError() .
+
+ ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
+ Why ? : making this distinction requires a header.
+ Header management is intentionally delegated to the user layer, which can better manage special cases.
+*/
+FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
+ const void* cSrc, size_t cSrcSize);
+
+
+/*-*****************************************
+* Tool functions
+******************************************/
+FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
+
+/* Error Management */
+FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
+FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
+
+
+/*-*****************************************
+* FSE advanced functions
+******************************************/
+/*! FSE_compress2() :
+ Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
+ Both parameters can be defined as '0' to mean : use default value
+ @return : size of compressed data
+ Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
+ if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
+ if FSE_isError(return), it's an error code.
+*/
+FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+
+
+/*-*****************************************
+* FSE detailed API
+******************************************/
+/*!
+FSE_compress() does the following:
+1. count symbol occurrence from source[] into table count[] (see hist.h)
+2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
+3. save normalized counters to memory buffer using writeNCount()
+4. build encoding table 'CTable' from normalized counters
+5. encode the data stream using encoding table 'CTable'
+
+FSE_decompress() does the following:
+1. read normalized counters with readNCount()
+2. build decoding table 'DTable' from normalized counters
+3. decode the data stream using decoding table 'DTable'
+
+The following API allows targeting specific sub-functions for advanced tasks.
+For example, it's possible to compress several blocks using the same 'CTable',
+or to save and provide normalized distribution using external method.
+*/
+
+/* *** COMPRESSION *** */
+
+/*! FSE_optimalTableLog():
+ dynamically downsize 'tableLog' when conditions are met.
+ It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
+ @return : recommended tableLog (necessarily <= 'maxTableLog') */
+FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_normalizeCount():
+ normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
+ 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
+ @return : tableLog,
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
+ const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_NCountWriteBound():
+ Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
+ Typically useful for allocation purpose. */
+FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_writeNCount():
+ Compactly save 'normalizedCounter' into 'buffer'.
+ @return : size of the compressed table,
+ or an errorCode, which can be tested using FSE_isError(). */
+FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+ const short* normalizedCounter,
+ unsigned maxSymbolValue, unsigned tableLog);
+
+/*! Constructor and Destructor of FSE_CTable.
+ Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
+typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
+FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
+FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
+
+/*! FSE_buildCTable():
+ Builds `ct`, which must be already allocated, using FSE_createCTable().
+ @return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_compress_usingCTable():
+ Compress `src` using `ct` into `dst` which must be already allocated.
+ @return : size of compressed data (<= `dstCapacity`),
+ or 0 if compressed data could not fit into `dst`,
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
+
+/*!
+Tutorial :
+----------
+The first step is to count all symbols. FSE_count() does this job very fast.
+Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
+'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
+maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
+FSE_count() will return the number of occurrence of the most frequent symbol.
+This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+The next step is to normalize the frequencies.
+FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
+It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
+You can use 'tableLog'==0 to mean "use default tableLog value".
+If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
+which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
+
+The result of FSE_normalizeCount() will be saved into a table,
+called 'normalizedCounter', which is a table of signed short.
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
+The return value is tableLog if everything proceeded as expected.
+It is 0 if there is a single symbol within distribution.
+If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
+'buffer' must be already allocated.
+For guaranteed success, buffer size must be at least FSE_headerBound().
+The result of the function is the number of bytes written into 'buffer'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
+
+'normalizedCounter' can then be used to create the compression table 'CTable'.
+The space required by 'CTable' must be already allocated, using FSE_createCTable().
+You can then use FSE_buildCTable() to fill 'CTable'.
+If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
+
+'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
+Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
+The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
+If it returns '0', compressed data could not fit into 'dst'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+*/
+
+
+/* *** DECOMPRESSION *** */
+
+/*! FSE_readNCount():
+ Read compactly saved 'normalizedCounter' from 'rBuffer'.
+ @return : size read from 'rBuffer',
+ or an errorCode, which can be tested using FSE_isError().
+ maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
+FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
+ unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
+ const void* rBuffer, size_t rBuffSize);
+
+/*! Constructor and Destructor of FSE_DTable.
+ Note that its size depends on 'tableLog' */
+typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
+FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
+FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
+
+/*! FSE_buildDTable():
+ Builds 'dt', which must be already allocated, using FSE_createDTable().
+ return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_decompress_usingDTable():
+ Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
+ into `dst` which must be already allocated.
+ @return : size of regenerated data (necessarily <= `dstCapacity`),
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
+
+/*!
+Tutorial :
+----------
+(Note : these functions only decompress FSE-compressed blocks.
+ If block is uncompressed, use memcpy() instead
+ If block is a single repeated byte, use memset() instead )
+
+The first step is to obtain the normalized frequencies of symbols.
+This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
+In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
+or size the table to handle worst case situations (typically 256).
+FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
+The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
+Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
+This is performed by the function FSE_buildDTable().
+The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
+`cSrcSize` must be strictly correct, otherwise decompression will fail.
+FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
+If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
+*/
+
+#endif /* FSE_H */
+
+#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
+#define FSE_H_FSE_STATIC_LINKING_ONLY
+
+/* *** Dependency *** */
+#include "bitstream.h"
+
+
+/* *****************************************
+* Static allocation
+*******************************************/
+/* FSE buffer bounds */
+#define FSE_NCOUNTBOUND 512
+#define FSE_BLOCKBOUND(size) (size + (size>>7))
+#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+
+/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
+#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
+#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<maxTableLog))
+
+/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
+#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
+#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
+
+
+/* *****************************************
+ * FSE advanced API
+ ***************************************** */
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
+/**< same as FSE_optimalTableLog(), which used `minus==2` */
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
+ */
+#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
+/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
+
+size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
+/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` must be >= `(1<<tableLog)`.
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
+/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
+
+size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
+/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
+/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
+
+typedef enum {
+ FSE_repeat_none, /**< Cannot use the previous table */
+ FSE_repeat_check, /**< Can use the previous table but it must be checked */
+ FSE_repeat_valid /**< Can use the previous table and it is asumed to be valid */
+ } FSE_repeat;
+
+/* *****************************************
+* FSE symbol compression API
+*******************************************/
+/*!
+ This API consists of small unitary functions, which highly benefit from being inlined.
+ Hence their body are included in next section.
+*/
+typedef struct {
+ ptrdiff_t value;
+ const void* stateTable;
+ const void* symbolTT;
+ unsigned stateLog;
+} FSE_CState_t;
+
+static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
+
+static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
+
+static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
+
+/**<
+These functions are inner components of FSE_compress_usingCTable().
+They allow the creation of custom streams, mixing multiple tables and bit sources.
+
+A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
+So the first symbol you will encode is the last you will decode, like a LIFO stack.
+
+You will need a few variables to track your CStream. They are :
+
+FSE_CTable ct; // Provided by FSE_buildCTable()
+BIT_CStream_t bitStream; // bitStream tracking structure
+FSE_CState_t state; // State tracking structure (can have several)
+
+
+The first thing to do is to init bitStream and state.
+ size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
+ FSE_initCState(&state, ct);
+
+Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
+You can then encode your input data, byte after byte.
+FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
+Remember decoding will be done in reverse direction.
+ FSE_encodeByte(&bitStream, &state, symbol);
+
+At any time, you can also add any bit sequence.
+Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
+ BIT_addBits(&bitStream, bitField, nbBits);
+
+The above methods don't commit data to memory, they just store it into local register, for speed.
+Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+Writing data to memory is a manual operation, performed by the flushBits function.
+ BIT_flushBits(&bitStream);
+
+Your last FSE encoding operation shall be to flush your last state value(s).
+ FSE_flushState(&bitStream, &state);
+
+Finally, you must close the bitStream.
+The function returns the size of CStream in bytes.
+If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
+If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
+ size_t size = BIT_closeCStream(&bitStream);
+*/
+
+
+/* *****************************************
+* FSE symbol decompression API
+*******************************************/
+typedef struct {
+ size_t state;
+ const void* table; /* precise table may vary, depending on U16 */
+} FSE_DState_t;
+
+
+static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
+
+static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+
+static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
+
+/**<
+Let's now decompose FSE_decompress_usingDTable() into its unitary components.
+You will decode FSE-encoded symbols from the bitStream,
+and also any other bitFields you put in, **in reverse order**.
+
+You will need a few variables to track your bitStream. They are :
+
+BIT_DStream_t DStream; // Stream context
+FSE_DState_t DState; // State context. Multiple ones are possible
+FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
+
+The first thing to do is to init the bitStream.
+ errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
+
+You should then retrieve your initial state(s)
+(in reverse flushing order if you have several ones) :
+ errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
+
+You can then decode your data, symbol after symbol.
+For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
+Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
+ unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
+
+You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
+Note : maximum allowed nbBits is 25, for 32-bits compatibility
+ size_t bitField = BIT_readBits(&DStream, nbBits);
+
+All above operations only read from local register (which size depends on size_t).
+Refueling the register from memory is manually performed by the reload method.
+ endSignal = FSE_reloadDStream(&DStream);
+
+BIT_reloadDStream() result tells if there is still some more data to read from DStream.
+BIT_DStream_unfinished : there is still some data left into the DStream.
+BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
+BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
+BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
+
+When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
+to properly detect the exact end of stream.
+After each decoded symbol, check if DStream is fully consumed using this simple test :
+ BIT_reloadDStream(&DStream) >= BIT_DStream_completed
+
+When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
+Checking if DStream has reached its end is performed by :
+ BIT_endOfDStream(&DStream);
+Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
+ FSE_endOfDState(&DState);
+*/
+
+
+/* *****************************************
+* FSE unsafe API
+*******************************************/
+static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
+
+
+/* *****************************************
+* Implementation of inlined functions
+*******************************************/
+typedef struct {
+ int deltaFindState;
+ U32 deltaNbBits;
+} FSE_symbolCompressionTransform; /* total 8 bytes */
+
+MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
+{
+ const void* ptr = ct;
+ const U16* u16ptr = (const U16*) ptr;
+ const U32 tableLog = MEM_read16(ptr);
+ statePtr->value = (ptrdiff_t)1<<tableLog;
+ statePtr->stateTable = u16ptr+2;
+ statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
+ statePtr->stateLog = tableLog;
+}
+
+
+/*! FSE_initCState2() :
+* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
+* uses the smallest state value possible, saving the cost of this symbol */
+MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
+{
+ FSE_initCState(statePtr, ct);
+ { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+ const U16* stateTable = (const U16*)(statePtr->stateTable);
+ U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
+ statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
+ statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+ }
+}
+
+MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
+{
+ FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+ const U16* const stateTable = (const U16*)(statePtr->stateTable);
+ U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
+ BIT_addBits(bitC, statePtr->value, nbBitsOut);
+ statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+}
+
+MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
+{
+ BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
+ BIT_flushBits(bitC);
+}
+
+
+/* FSE_getMaxNbBits() :
+ * Approximate maximum cost of a symbol, in bits.
+ * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
+{
+ const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+ return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
+}
+
+/* FSE_bitCost() :
+ * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
+{
+ const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+ U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
+ U32 const threshold = (minNbBits+1) << 16;
+ assert(tableLog < 16);
+ assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
+ { U32 const tableSize = 1 << tableLog;
+ U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
+ U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
+ U32 const bitMultiplier = 1 << accuracyLog;
+ assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
+ assert(normalizedDeltaFromThreshold <= bitMultiplier);
+ return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
+ }
+}
+
+
+/* ====== Decompression ====== */
+
+typedef struct {
+ U16 tableLog;
+ U16 fastMode;
+} FSE_DTableHeader; /* sizeof U32 */
+
+typedef struct
+{
+ unsigned short newState;
+ unsigned char symbol;
+ unsigned char nbBits;
+} FSE_decode_t; /* size == U32 */
+
+MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
+{
+ const void* ptr = dt;
+ const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
+ DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+ BIT_reloadDStream(bitD);
+ DStatePtr->table = dt + 1;
+}
+
+MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ return DInfo.symbol;
+}
+
+MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+ DStatePtr->state = DInfo.newState + lowBits;
+}
+
+MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ BYTE const symbol = DInfo.symbol;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+
+ DStatePtr->state = DInfo.newState + lowBits;
+ return symbol;
+}
+
+/*! FSE_decodeSymbolFast() :
+ unsafe, only works if no symbol has a probability > 50% */
+MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ BYTE const symbol = DInfo.symbol;
+ size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
+
+ DStatePtr->state = DInfo.newState + lowBits;
+ return symbol;
+}
+
+MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
+{
+ return DStatePtr->state == 0;
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/* **************************************************************
+* Tuning parameters
+****************************************************************/
+/*!MEMORY_USAGE :
+* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+* Increasing memory usage improves compression ratio
+* Reduced memory usage can improve speed, due to cache effect
+* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+#ifndef FSE_MAX_MEMORY_USAGE
+# define FSE_MAX_MEMORY_USAGE 14
+#endif
+#ifndef FSE_DEFAULT_MEMORY_USAGE
+# define FSE_DEFAULT_MEMORY_USAGE 13
+#endif
+
+/*!FSE_MAX_SYMBOL_VALUE :
+* Maximum symbol value authorized.
+* Required for proper stack allocation */
+#ifndef FSE_MAX_SYMBOL_VALUE
+# define FSE_MAX_SYMBOL_VALUE 255
+#endif
+
+/* **************************************************************
+* template functions type & suffix
+****************************************************************/
+#define FSE_FUNCTION_TYPE BYTE
+#define FSE_FUNCTION_EXTENSION
+#define FSE_DECODE_TYPE FSE_decode_t
+
+
+#endif /* !FSE_COMMONDEFS_ONLY */
+
+
+/* ***************************************************************
+* Constants
+*****************************************************************/
+#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
+#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
+#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
+#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
+#define FSE_MIN_TABLELOG 5
+
+#define FSE_TABLELOG_ABSOLUTE_MAX 15
+#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
+# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
+#endif
+
+#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
+
+
+#endif /* FSE_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/fse_decompress.c b/Utilities/cmzstd/lib/common/fse_decompress.c
new file mode 100644
index 000000000..72bbead5b
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/fse_decompress.c
@@ -0,0 +1,309 @@
+/* ******************************************************************
+ FSE : Finite State Entropy decoder
+ Copyright (C) 2013-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memcpy, memset */
+#include "bitstream.h"
+#include "compiler.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
+
+/* check and forward error code */
+#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
+
+
+/* **************************************************************
+* Templates
+****************************************************************/
+/*
+ designed to be included
+ for type-specific functions (template emulation in C)
+ Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+# error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+# error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+FSE_DTable* FSE_createDTable (unsigned tableLog)
+{
+ if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
+ return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
+}
+
+void FSE_freeDTable (FSE_DTable* dt)
+{
+ free(dt);
+}
+
+size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
+ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
+ U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
+
+ U32 const maxSV1 = maxSymbolValue + 1;
+ U32 const tableSize = 1 << tableLog;
+ U32 highThreshold = tableSize-1;
+
+ /* Sanity Checks */
+ if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+
+ /* Init, lay down lowprob symbols */
+ { FSE_DTableHeader DTableH;
+ DTableH.tableLog = (U16)tableLog;
+ DTableH.fastMode = 1;
+ { S16 const largeLimit= (S16)(1 << (tableLog-1));
+ U32 s;
+ for (s=0; s<maxSV1; s++) {
+ if (normalizedCounter[s]==-1) {
+ tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
+ symbolNext[s] = 1;
+ } else {
+ if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+ symbolNext[s] = normalizedCounter[s];
+ } } }
+ memcpy(dt, &DTableH, sizeof(DTableH));
+ }
+
+ /* Spread symbols */
+ { U32 const tableMask = tableSize-1;
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 s, position = 0;
+ for (s=0; s<maxSV1; s++) {
+ int i;
+ for (i=0; i<normalizedCounter[s]; i++) {
+ tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
+ position = (position + step) & tableMask;
+ while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
+ } }
+ if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+ }
+
+ /* Build Decoding table */
+ { U32 u;
+ for (u=0; u<tableSize; u++) {
+ FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
+ U32 const nextState = symbolNext[symbol]++;
+ tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+ tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+ } }
+
+ return 0;
+}
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/*-*******************************************************
+* Decompression (Byte symbols)
+*********************************************************/
+size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
+{
+ void* ptr = dt;
+ FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+ void* dPtr = dt + 1;
+ FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
+
+ DTableH->tableLog = 0;
+ DTableH->fastMode = 0;
+
+ cell->newState = 0;
+ cell->symbol = symbolValue;
+ cell->nbBits = 0;
+
+ return 0;
+}
+
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
+{
+ void* ptr = dt;
+ FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+ void* dPtr = dt + 1;
+ FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
+ const unsigned tableSize = 1 << nbBits;
+ const unsigned tableMask = tableSize - 1;
+ const unsigned maxSV1 = tableMask+1;
+ unsigned s;
+
+ /* Sanity checks */
+ if (nbBits < 1) return ERROR(GENERIC); /* min size */
+
+ /* Build Decoding Table */
+ DTableH->tableLog = (U16)nbBits;
+ DTableH->fastMode = 1;
+ for (s=0; s<maxSV1; s++) {
+ dinfo[s].newState = 0;
+ dinfo[s].symbol = (BYTE)s;
+ dinfo[s].nbBits = (BYTE)nbBits;
+ }
+
+ return 0;
+}
+
+FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
+ void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const FSE_DTable* dt, const unsigned fast)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const omax = op + maxDstSize;
+ BYTE* const olimit = omax-3;
+
+ BIT_DStream_t bitD;
+ FSE_DState_t state1;
+ FSE_DState_t state2;
+
+ /* Init */
+ CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
+
+ FSE_initDState(&state1, &bitD, dt);
+ FSE_initDState(&state2, &bitD, dt);
+
+#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
+
+ /* 4 symbols per loop */
+ for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
+ op[0] = FSE_GETSYMBOL(&state1);
+
+ if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ BIT_reloadDStream(&bitD);
+
+ op[1] = FSE_GETSYMBOL(&state2);
+
+ if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
+
+ op[2] = FSE_GETSYMBOL(&state1);
+
+ if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ BIT_reloadDStream(&bitD);
+
+ op[3] = FSE_GETSYMBOL(&state2);
+ }
+
+ /* tail */
+ /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
+ while (1) {
+ if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ *op++ = FSE_GETSYMBOL(&state1);
+ if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ *op++ = FSE_GETSYMBOL(&state2);
+ break;
+ }
+
+ if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ *op++ = FSE_GETSYMBOL(&state2);
+ if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ *op++ = FSE_GETSYMBOL(&state1);
+ break;
+ } }
+
+ return op-ostart;
+}
+
+
+size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
+ const void* cSrc, size_t cSrcSize,
+ const FSE_DTable* dt)
+{
+ const void* ptr = dt;
+ const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
+ const U32 fastMode = DTableH->fastMode;
+
+ /* select fast mode (static) */
+ if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
+ return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
+}
+
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
+{
+ const BYTE* const istart = (const BYTE*)cSrc;
+ const BYTE* ip = istart;
+ short counting[FSE_MAX_SYMBOL_VALUE+1];
+ unsigned tableLog;
+ unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+
+ /* normal FSE decoding mode */
+ size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
+ if (FSE_isError(NCountLength)) return NCountLength;
+ //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
+ if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+ ip += NCountLength;
+ cSrcSize -= NCountLength;
+
+ CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
+
+ return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
+}
+
+
+typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
+
+size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
+{
+ DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */
+ return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
+}
+
+
+
+#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/Utilities/cmzstd/lib/common/huf.h b/Utilities/cmzstd/lib/common/huf.h
new file mode 100644
index 000000000..6b572c448
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/huf.h
@@ -0,0 +1,358 @@
+/* ******************************************************************
+ huff0 huffman codec,
+ part of Finite State Entropy library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef HUF_H_298734234
+#define HUF_H_298734234
+
+/* *** Dependencies *** */
+#include <stddef.h> /* size_t */
+
+
+/* *** library symbols visibility *** */
+/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
+ * HUF symbols remain "private" (internal symbols for library only).
+ * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
+# define HUF_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
+#else
+# define HUF_PUBLIC_API
+#endif
+
+
+/* ========================== */
+/* *** simple functions *** */
+/* ========================== */
+
+/** HUF_compress() :
+ * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
+ * 'dst' buffer must be already allocated.
+ * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
+ * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
+ * @return : size of compressed data (<= `dstCapacity`).
+ * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+ * if HUF_isError(return), compression failed (more details using HUF_getErrorName())
+ */
+HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+/** HUF_decompress() :
+ * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
+ * into already allocated buffer 'dst', of minimum size 'dstSize'.
+ * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
+ * Note : in contrast with FSE, HUF_decompress can regenerate
+ * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
+ * because it knows size to regenerate (originalSize).
+ * @return : size of regenerated data (== originalSize),
+ * or an error code, which can be tested using HUF_isError()
+ */
+HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
+ const void* cSrc, size_t cSrcSize);
+
+
+/* *** Tool functions *** */
+#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
+HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
+
+/* Error Management */
+HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
+HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */
+
+
+/* *** Advanced function *** */
+
+/** HUF_compress2() :
+ * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
+ * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
+ * `tableLog` must be `<= HUF_TABLELOG_MAX` . */
+HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog);
+
+/** HUF_compress4X_wksp() :
+ * Same as HUF_compress2(), but uses externally allocated `workSpace`.
+ * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */
+#define HUF_WORKSPACE_SIZE (6 << 10)
+#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
+HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize);
+
+#endif /* HUF_H_298734234 */
+
+/* ******************************************************************
+ * WARNING !!
+ * The following section contains advanced and experimental definitions
+ * which shall never be used in the context of a dynamic library,
+ * because they are not guaranteed to remain stable in the future.
+ * Only consider them in association with static linking.
+ * *****************************************************************/
+#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
+#define HUF_H_HUF_STATIC_LINKING_ONLY
+
+/* *** Dependencies *** */
+#include "mem.h" /* U32 */
+
+
+/* *** Constants *** */
+#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
+#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
+#define HUF_SYMBOLVALUE_MAX 255
+
+#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
+#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
+# error "HUF_TABLELOG_MAX is too large !"
+#endif
+
+
+/* ****************************************
+* Static allocation
+******************************************/
+/* HUF buffer bounds */
+#define HUF_CTABLEBOUND 129
+#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */
+#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+
+/* static allocation of HUF's Compression Table */
+#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */
+#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32))
+#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
+ U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \
+ void* name##hv = &(name##hb); \
+ HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
+
+/* static allocation of HUF's DTable */
+typedef U32 HUF_DTable;
+#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
+#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
+ HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
+#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
+ HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
+
+
+/* ****************************************
+* Advanced decompression functions
+******************************************/
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
+#endif
+
+
+/* ****************************************
+ * HUF detailed API
+ * ****************************************/
+
+/*! HUF_compress() does the following:
+ * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
+ * 2. (optional) refine tableLog using HUF_optimalTableLog()
+ * 3. build Huffman table from count using HUF_buildCTable()
+ * 4. save Huffman table to memory buffer using HUF_writeCTable()
+ * 5. encode the data stream using HUF_compress4X_usingCTable()
+ *
+ * The following API allows targeting specific sub-functions for advanced tasks.
+ * For example, it's possible to compress several blocks using the same 'CTable',
+ * or to save and regenerate 'CTable' using external methods.
+ */
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
+size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+
+typedef enum {
+ HUF_repeat_none, /**< Cannot use the previous table */
+ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
+ HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */
+ } HUF_repeat;
+/** HUF_compress4X_repeat() :
+ * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ * If it uses hufTable it does not modify hufTable or repeat.
+ * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ * If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+/** HUF_buildCTable_wksp() :
+ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
+ */
+#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
+#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
+size_t HUF_buildCTable_wksp (HUF_CElt* tree,
+ const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
+ void* workSpace, size_t wkspSize);
+
+/*! HUF_readStats() :
+ * Read compact Huffman tree, saved by HUF_writeCTable().
+ * `huffWeight` is destination buffer.
+ * @return : size read from `src` , or an error Code .
+ * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
+ U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
+ const void* src, size_t srcSize);
+
+/** HUF_readCTable() :
+ * Loading a CTable saved with HUF_writeCTable() */
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
+
+/** HUF_getNbBits() :
+ * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
+ * Note 1 : is not inlined, as HUF_CElt definition is private
+ * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue);
+
+/*
+ * HUF_decompress() does the following:
+ * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
+ * 2. build Huffman table from save, using HUF_readDTableX?()
+ * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
+ */
+
+/** HUF_selectDecoder() :
+ * Tells which decoder is likely to decode faster,
+ * based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ * Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
+
+/**
+ * The minimum workspace size for the `workSpace` used in
+ * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
+ *
+ * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
+ * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
+ * Buffer overflow errors may potentially occur if code modifications result in
+ * a required workspace size greater than that specified in the following
+ * macro.
+ */
+#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+
+/* ====================== */
+/* single stream variants */
+/* ====================== */
+
+size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+/** HUF_compress1X_repeat() :
+ * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ * If it uses hufTable it does not modify hufTable or repeat.
+ * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ * If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
+#endif
+
+size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+/* BMI2 variants.
+ * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
+ */
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+#endif
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+
+#endif /* HUF_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/mem.h b/Utilities/cmzstd/lib/common/mem.h
new file mode 100644
index 000000000..5da248756
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/mem.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef MEM_H_MODULE
+#define MEM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*-****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t, ptrdiff_t */
+#include <string.h> /* memcpy */
+
+
+/*-****************************************
+* Compiler specifics
+******************************************/
+#if defined(_MSC_VER) /* Visual Studio */
+# include <stdlib.h> /* _byteswap_ulong */
+# include <intrin.h> /* _byteswap_* */
+#endif
+#if defined(__GNUC__)
+# define MEM_STATIC static __inline __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define MEM_STATIC static inline
+#elif defined(_MSC_VER)
+# define MEM_STATIC static __inline
+#else
+# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0 /* compat. with non-clang compilers */
+#endif
+
+/* code only tested on 32 and 64 bits systems */
+#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
+MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
+
+
+/*-**************************************************************
+* Basic Types
+*****************************************************************/
+#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef int16_t S16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+ typedef int64_t S64;
+#else
+# include <limits.h>
+#if CHAR_BIT != 8
+# error "this implementation requires char to be exactly 8-bit type"
+#endif
+ typedef unsigned char BYTE;
+#if USHRT_MAX != 65535
+# error "this implementation requires short to be exactly 16-bit type"
+#endif
+ typedef unsigned short U16;
+ typedef signed short S16;
+#if UINT_MAX != 4294967295
+# error "this implementation requires int to be exactly 32-bit type"
+#endif
+ typedef unsigned int U32;
+ typedef signed int S32;
+/* note : there are no limits defined for long long type in C90.
+ * limits exist in C99, however, in such case, <stdint.h> is preferred */
+ typedef unsigned long long U64;
+ typedef signed long long S64;
+#endif
+
+
+/*-**************************************************************
+* Memory I/O
+*****************************************************************/
+/* MEM_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method is portable but violate C standard.
+ * It can generate buggy code on targets depending on alignment.
+ * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)
+ * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define MEM_FORCE_MEMORY_ACCESS 2
+# elif defined(__INTEL_COMPILER) || defined(__GNUC__)
+# define MEM_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
+MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
+
+MEM_STATIC unsigned MEM_isLittleEndian(void)
+{
+ const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
+
+/* violates C standard, by lying on structure alignment.
+Only use if no other choice to achieve best performance on target platform */
+MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
+MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
+MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
+MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
+
+#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
+ __pragma( pack(push, 1) )
+ typedef struct { U16 v; } unalign16;
+ typedef struct { U32 v; } unalign32;
+ typedef struct { U64 v; } unalign64;
+ typedef struct { size_t v; } unalignArch;
+ __pragma( pack(pop) )
+#else
+ typedef struct { U16 v; } __attribute__((packed)) unalign16;
+ typedef struct { U32 v; } __attribute__((packed)) unalign32;
+ typedef struct { U64 v; } __attribute__((packed)) unalign64;
+ typedef struct { size_t v; } __attribute__((packed)) unalignArch;
+#endif
+
+MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }
+MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }
+MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }
+MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }
+
+#else
+
+/* default method, safe and standard.
+ can sometimes prove slower */
+
+MEM_STATIC U16 MEM_read16(const void* memPtr)
+{
+ U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U32 MEM_read32(const void* memPtr)
+{
+ U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U64 MEM_read64(const void* memPtr)
+{
+ U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC size_t MEM_readST(const void* memPtr)
+{
+ size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write32(void* memPtr, U32 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write64(void* memPtr, U64 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+#endif /* MEM_FORCE_MEMORY_ACCESS */
+
+MEM_STATIC U32 MEM_swap32(U32 in)
+{
+#if defined(_MSC_VER) /* Visual Studio */
+ return _byteswap_ulong(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+ || (defined(__clang__) && __has_builtin(__builtin_bswap32))
+ return __builtin_bswap32(in);
+#else
+ return ((in << 24) & 0xff000000 ) |
+ ((in << 8) & 0x00ff0000 ) |
+ ((in >> 8) & 0x0000ff00 ) |
+ ((in >> 24) & 0x000000ff );
+#endif
+}
+
+MEM_STATIC U64 MEM_swap64(U64 in)
+{
+#if defined(_MSC_VER) /* Visual Studio */
+ return _byteswap_uint64(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+ || (defined(__clang__) && __has_builtin(__builtin_bswap64))
+ return __builtin_bswap64(in);
+#else
+ return ((in << 56) & 0xff00000000000000ULL) |
+ ((in << 40) & 0x00ff000000000000ULL) |
+ ((in << 24) & 0x0000ff0000000000ULL) |
+ ((in << 8) & 0x000000ff00000000ULL) |
+ ((in >> 8) & 0x00000000ff000000ULL) |
+ ((in >> 24) & 0x0000000000ff0000ULL) |
+ ((in >> 40) & 0x000000000000ff00ULL) |
+ ((in >> 56) & 0x00000000000000ffULL);
+#endif
+}
+
+MEM_STATIC size_t MEM_swapST(size_t in)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_swap32((U32)in);
+ else
+ return (size_t)MEM_swap64((U64)in);
+}
+
+/*=== Little endian r/w ===*/
+
+MEM_STATIC U16 MEM_readLE16(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read16(memPtr);
+ else {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)(p[0] + (p[1]<<8));
+ }
+}
+
+MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
+{
+ if (MEM_isLittleEndian()) {
+ MEM_write16(memPtr, val);
+ } else {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE)val;
+ p[1] = (BYTE)(val>>8);
+ }
+}
+
+MEM_STATIC U32 MEM_readLE24(const void* memPtr)
+{
+ return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+}
+
+MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
+{
+ MEM_writeLE16(memPtr, (U16)val);
+ ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
+}
+
+MEM_STATIC U32 MEM_readLE32(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read32(memPtr);
+ else
+ return MEM_swap32(MEM_read32(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
+{
+ if (MEM_isLittleEndian())
+ MEM_write32(memPtr, val32);
+ else
+ MEM_write32(memPtr, MEM_swap32(val32));
+}
+
+MEM_STATIC U64 MEM_readLE64(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read64(memPtr);
+ else
+ return MEM_swap64(MEM_read64(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
+{
+ if (MEM_isLittleEndian())
+ MEM_write64(memPtr, val64);
+ else
+ MEM_write64(memPtr, MEM_swap64(val64));
+}
+
+MEM_STATIC size_t MEM_readLEST(const void* memPtr)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_readLE32(memPtr);
+ else
+ return (size_t)MEM_readLE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
+{
+ if (MEM_32bits())
+ MEM_writeLE32(memPtr, (U32)val);
+ else
+ MEM_writeLE64(memPtr, (U64)val);
+}
+
+/*=== Big endian r/w ===*/
+
+MEM_STATIC U32 MEM_readBE32(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_swap32(MEM_read32(memPtr));
+ else
+ return MEM_read32(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
+{
+ if (MEM_isLittleEndian())
+ MEM_write32(memPtr, MEM_swap32(val32));
+ else
+ MEM_write32(memPtr, val32);
+}
+
+MEM_STATIC U64 MEM_readBE64(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_swap64(MEM_read64(memPtr));
+ else
+ return MEM_read64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
+{
+ if (MEM_isLittleEndian())
+ MEM_write64(memPtr, MEM_swap64(val64));
+ else
+ MEM_write64(memPtr, val64);
+}
+
+MEM_STATIC size_t MEM_readBEST(const void* memPtr)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_readBE32(memPtr);
+ else
+ return (size_t)MEM_readBE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
+{
+ if (MEM_32bits())
+ MEM_writeBE32(memPtr, (U32)val);
+ else
+ MEM_writeBE64(memPtr, (U64)val);
+}
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* MEM_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/pool.c b/Utilities/cmzstd/lib/common/pool.c
new file mode 100644
index 000000000..7a8294543
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/pool.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ====== Dependencies ======= */
+#include <stddef.h> /* size_t */
+#include "debug.h" /* assert */
+#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */
+#include "pool.h"
+
+/* ====== Compiler specifics ====== */
+#if defined(_MSC_VER)
+# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+#ifdef ZSTD_MULTITHREAD
+
+#include "threading.h" /* pthread adaptation */
+
+/* A job is a function and an opaque argument */
+typedef struct POOL_job_s {
+ POOL_function function;
+ void *opaque;
+} POOL_job;
+
+struct POOL_ctx_s {
+ ZSTD_customMem customMem;
+ /* Keep track of the threads */
+ ZSTD_pthread_t* threads;
+ size_t threadCapacity;
+ size_t threadLimit;
+
+ /* The queue is a circular buffer */
+ POOL_job *queue;
+ size_t queueHead;
+ size_t queueTail;
+ size_t queueSize;
+
+ /* The number of threads working on jobs */
+ size_t numThreadsBusy;
+ /* Indicates if the queue is empty */
+ int queueEmpty;
+
+ /* The mutex protects the queue */
+ ZSTD_pthread_mutex_t queueMutex;
+ /* Condition variable for pushers to wait on when the queue is full */
+ ZSTD_pthread_cond_t queuePushCond;
+ /* Condition variables for poppers to wait on when the queue is empty */
+ ZSTD_pthread_cond_t queuePopCond;
+ /* Indicates if the queue is shutting down */
+ int shutdown;
+};
+
+/* POOL_thread() :
+ * Work thread for the thread pool.
+ * Waits for jobs and executes them.
+ * @returns : NULL on failure else non-null.
+ */
+static void* POOL_thread(void* opaque) {
+ POOL_ctx* const ctx = (POOL_ctx*)opaque;
+ if (!ctx) { return NULL; }
+ for (;;) {
+ /* Lock the mutex and wait for a non-empty queue or until shutdown */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+
+ while ( ctx->queueEmpty
+ || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
+ if (ctx->shutdown) {
+ /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
+ * a few threads will be shutdown while !queueEmpty,
+ * but enough threads will remain active to finish the queue */
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return opaque;
+ }
+ ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
+ }
+ /* Pop a job off the queue */
+ { POOL_job const job = ctx->queue[ctx->queueHead];
+ ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
+ ctx->numThreadsBusy++;
+ ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
+ /* Unlock the mutex, signal a pusher, and run the job */
+ ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+
+ job.function(job.opaque);
+
+ /* If the intended queue size was 0, signal after finishing job */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ ctx->numThreadsBusy--;
+ if (ctx->queueSize == 1) {
+ ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+ }
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ }
+ } /* for (;;) */
+ assert(0); /* Unreachable */
+}
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+ return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+ ZSTD_customMem customMem) {
+ POOL_ctx* ctx;
+ /* Check parameters */
+ if (!numThreads) { return NULL; }
+ /* Allocate the context and zero initialize */
+ ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
+ if (!ctx) { return NULL; }
+ /* Initialize the job queue.
+ * It needs one extra space since one space is wasted to differentiate
+ * empty and full queues.
+ */
+ ctx->queueSize = queueSize + 1;
+ ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
+ ctx->queueHead = 0;
+ ctx->queueTail = 0;
+ ctx->numThreadsBusy = 0;
+ ctx->queueEmpty = 1;
+ (void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
+ (void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
+ (void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
+ ctx->shutdown = 0;
+ /* Allocate space for the thread handles */
+ ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
+ ctx->threadCapacity = 0;
+ ctx->customMem = customMem;
+ /* Check for errors */
+ if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
+ /* Initialize the threads */
+ { size_t i;
+ for (i = 0; i < numThreads; ++i) {
+ if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
+ ctx->threadCapacity = i;
+ POOL_free(ctx);
+ return NULL;
+ } }
+ ctx->threadCapacity = numThreads;
+ ctx->threadLimit = numThreads;
+ }
+ return ctx;
+}
+
+/*! POOL_join() :
+ Shutdown the queue, wake any sleeping threads, and join all of the threads.
+*/
+static void POOL_join(POOL_ctx* ctx) {
+ /* Shut down the queue */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ ctx->shutdown = 1;
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ /* Wake up sleeping threads */
+ ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
+ ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+ /* Join all of the threads */
+ { size_t i;
+ for (i = 0; i < ctx->threadCapacity; ++i) {
+ ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */
+ } }
+}
+
+void POOL_free(POOL_ctx *ctx) {
+ if (!ctx) { return; }
+ POOL_join(ctx);
+ ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
+ ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
+ ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
+ ZSTD_free(ctx->queue, ctx->customMem);
+ ZSTD_free(ctx->threads, ctx->customMem);
+ ZSTD_free(ctx, ctx->customMem);
+}
+
+
+
+size_t POOL_sizeof(POOL_ctx *ctx) {
+ if (ctx==NULL) return 0; /* supports sizeof NULL */
+ return sizeof(*ctx)
+ + ctx->queueSize * sizeof(POOL_job)
+ + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
+}
+
+
+/* @return : 0 on success, 1 on error */
+static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
+{
+ if (numThreads <= ctx->threadCapacity) {
+ if (!numThreads) return 1;
+ ctx->threadLimit = numThreads;
+ return 0;
+ }
+ /* numThreads > threadCapacity */
+ { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
+ if (!threadPool) return 1;
+ /* replace existing thread pool */
+ memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
+ ZSTD_free(ctx->threads, ctx->customMem);
+ ctx->threads = threadPool;
+ /* Initialize additional threads */
+ { size_t threadId;
+ for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
+ if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
+ ctx->threadCapacity = threadId;
+ return 1;
+ } }
+ } }
+ /* successfully expanded */
+ ctx->threadCapacity = numThreads;
+ ctx->threadLimit = numThreads;
+ return 0;
+}
+
+/* @return : 0 on success, 1 on error */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads)
+{
+ int result;
+ if (ctx==NULL) return 1;
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ result = POOL_resize_internal(ctx, numThreads);
+ ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return result;
+}
+
+/**
+ * Returns 1 if the queue is full and 0 otherwise.
+ *
+ * When queueSize is 1 (pool was created with an intended queueSize of 0),
+ * then a queue is empty if there is a thread free _and_ no job is waiting.
+ */
+static int isQueueFull(POOL_ctx const* ctx) {
+ if (ctx->queueSize > 1) {
+ return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
+ } else {
+ return (ctx->numThreadsBusy == ctx->threadLimit) ||
+ !ctx->queueEmpty;
+ }
+}
+
+
+static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
+{
+ POOL_job const job = {function, opaque};
+ assert(ctx != NULL);
+ if (ctx->shutdown) return;
+
+ ctx->queueEmpty = 0;
+ ctx->queue[ctx->queueTail] = job;
+ ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
+ ZSTD_pthread_cond_signal(&ctx->queuePopCond);
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+ assert(ctx != NULL);
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ /* Wait until there is space in the queue for the new job */
+ while (isQueueFull(ctx) && (!ctx->shutdown)) {
+ ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
+ }
+ POOL_add_internal(ctx, function, opaque);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+}
+
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+ assert(ctx != NULL);
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ if (isQueueFull(ctx)) {
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return 0;
+ }
+ POOL_add_internal(ctx, function, opaque);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return 1;
+}
+
+
+#else /* ZSTD_MULTITHREAD not defined */
+
+/* ========================== */
+/* No multi-threading support */
+/* ========================== */
+
+
+/* We don't need any data, but if it is empty, malloc() might return NULL. */
+struct POOL_ctx_s {
+ int dummy;
+};
+static POOL_ctx g_ctx;
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+ return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
+ (void)numThreads;
+ (void)queueSize;
+ (void)customMem;
+ return &g_ctx;
+}
+
+void POOL_free(POOL_ctx* ctx) {
+ assert(!ctx || ctx == &g_ctx);
+ (void)ctx;
+}
+
+int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
+ (void)ctx; (void)numThreads;
+ return 0;
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
+ (void)ctx;
+ function(opaque);
+}
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
+ (void)ctx;
+ function(opaque);
+ return 1;
+}
+
+size_t POOL_sizeof(POOL_ctx* ctx) {
+ if (ctx==NULL) return 0; /* supports sizeof NULL */
+ assert(ctx == &g_ctx);
+ return sizeof(*ctx);
+}
+
+#endif /* ZSTD_MULTITHREAD */
diff --git a/Utilities/cmzstd/lib/common/pool.h b/Utilities/cmzstd/lib/common/pool.h
new file mode 100644
index 000000000..458d37f13
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/pool.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef POOL_H
+#define POOL_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#include <stddef.h> /* size_t */
+#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */
+#include "zstd.h"
+
+typedef struct POOL_ctx_s POOL_ctx;
+
+/*! POOL_create() :
+ * Create a thread pool with at most `numThreads` threads.
+ * `numThreads` must be at least 1.
+ * The maximum number of queued jobs before blocking is `queueSize`.
+ * @return : POOL_ctx pointer on success, else NULL.
+*/
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+ ZSTD_customMem customMem);
+
+/*! POOL_free() :
+ * Free a thread pool returned by POOL_create().
+ */
+void POOL_free(POOL_ctx* ctx);
+
+/*! POOL_resize() :
+ * Expands or shrinks pool's number of threads.
+ * This is more efficient than releasing + creating a new context,
+ * since it tries to preserve and re-use existing threads.
+ * `numThreads` must be at least 1.
+ * @return : 0 when resize was successful,
+ * !0 (typically 1) if there is an error.
+ * note : only numThreads can be resized, queueSize remains unchanged.
+ */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads);
+
+/*! POOL_sizeof() :
+ * @return threadpool memory usage
+ * note : compatible with NULL (returns 0 in this case)
+ */
+size_t POOL_sizeof(POOL_ctx* ctx);
+
+/*! POOL_function :
+ * The function type that can be added to a thread pool.
+ */
+typedef void (*POOL_function)(void*);
+
+/*! POOL_add() :
+ * Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
+ * Possibly blocks until there is room in the queue.
+ * Note : The function may be executed asynchronously,
+ * therefore, `opaque` must live until function has been completed.
+ */
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+/*! POOL_tryAdd() :
+ * Add the job `function(opaque)` to thread pool _if_ a worker is available.
+ * Returns immediately even if not (does not block).
+ * @return : 1 if successful, 0 if not.
+ */
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
diff --git a/Utilities/cmzstd/lib/common/threading.c b/Utilities/cmzstd/lib/common/threading.c
new file mode 100644
index 000000000..8be8c8da9
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/threading.c
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+/**
+ * This file will hold wrapper for systems, which do not support pthreads
+ */
+
+/* create fake symbol to avoid empty trnaslation unit warning */
+int g_ZSTD_threading_useles_symbol;
+
+#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
+
+/**
+ * Windows minimalist Pthread Wrapper, based on :
+ * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
+ */
+
+
+/* === Dependencies === */
+#include <process.h>
+#include <errno.h>
+#include "threading.h"
+
+
+/* === Implementation === */
+
+static unsigned __stdcall worker(void *arg)
+{
+ ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg;
+ thread->arg = thread->start_routine(thread->arg);
+ return 0;
+}
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+ void* (*start_routine) (void*), void* arg)
+{
+ (void)unused;
+ thread->arg = arg;
+ thread->start_routine = start_routine;
+ thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL);
+
+ if (!thread->handle)
+ return errno;
+ else
+ return 0;
+}
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
+{
+ DWORD result;
+
+ if (!thread.handle) return 0;
+
+ result = WaitForSingleObject(thread.handle, INFINITE);
+ switch (result) {
+ case WAIT_OBJECT_0:
+ if (value_ptr) *value_ptr = thread.arg;
+ return 0;
+ case WAIT_ABANDONED:
+ return EINVAL;
+ default:
+ return GetLastError();
+ }
+}
+
+#endif /* ZSTD_MULTITHREAD */
diff --git a/Utilities/cmzstd/lib/common/threading.h b/Utilities/cmzstd/lib/common/threading.h
new file mode 100644
index 000000000..d806c89d0
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/threading.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+#ifndef THREADING_H_938743
+#define THREADING_H_938743
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
+
+/**
+ * Windows minimalist Pthread Wrapper, based on :
+ * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
+ */
+#ifdef WINVER
+# undef WINVER
+#endif
+#define WINVER 0x0600
+
+#ifdef _WIN32_WINNT
+# undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
+#include <windows.h>
+#undef ERROR
+#define ERROR(name) ZSTD_ERROR(name)
+
+
+/* mutex */
+#define ZSTD_pthread_mutex_t CRITICAL_SECTION
+#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0)
+#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
+#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
+#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
+
+/* condition variable */
+#define ZSTD_pthread_cond_t CONDITION_VARIABLE
+#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0)
+#define ZSTD_pthread_cond_destroy(a) ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
+#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
+#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
+
+/* ZSTD_pthread_create() and ZSTD_pthread_join() */
+typedef struct {
+ HANDLE handle;
+ void* (*start_routine)(void*);
+ void* arg;
+} ZSTD_pthread_t;
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+ void* (*start_routine) (void*), void* arg);
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
+
+/**
+ * add here more wrappers as required
+ */
+
+
+#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */
+/* === POSIX Systems === */
+# include <pthread.h>
+
+#define ZSTD_pthread_mutex_t pthread_mutex_t
+#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b))
+#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a))
+#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a))
+#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a))
+
+#define ZSTD_pthread_cond_t pthread_cond_t
+#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b))
+#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a))
+#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b))
+#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a))
+#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a))
+
+#define ZSTD_pthread_t pthread_t
+#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
+#define ZSTD_pthread_join(a, b) pthread_join((a),(b))
+
+#else /* ZSTD_MULTITHREAD not defined */
+/* No multithreading support */
+
+typedef int ZSTD_pthread_mutex_t;
+#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_mutex_destroy(a) ((void)(a))
+#define ZSTD_pthread_mutex_lock(a) ((void)(a))
+#define ZSTD_pthread_mutex_unlock(a) ((void)(a))
+
+typedef int ZSTD_pthread_cond_t;
+#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_cond_destroy(a) ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b))
+#define ZSTD_pthread_cond_signal(a) ((void)(a))
+#define ZSTD_pthread_cond_broadcast(a) ((void)(a))
+
+/* do not use ZSTD_pthread_t */
+
+#endif /* ZSTD_MULTITHREAD */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* THREADING_H_938743 */
diff --git a/Utilities/cmzstd/lib/common/xxhash.c b/Utilities/cmzstd/lib/common/xxhash.c
new file mode 100644
index 000000000..532b81619
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/xxhash.c
@@ -0,0 +1,876 @@
+/*
+* xxHash - Fast Hash algorithm
+* Copyright (C) 2012-2016, Yann Collet
+*
+* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+* OWNER 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.
+*
+* You can contact the author at :
+* - xxHash homepage: http://www.xxhash.com
+* - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+
+/* *************************************
+* Tuning parameters
+***************************************/
+/*!XXH_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
+ * It can generate buggy code on targets which do not support unaligned memory accesses.
+ * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
+ * See http://stackoverflow.com/a/32095106/646947 for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define XXH_FORCE_MEMORY_ACCESS 2
+# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
+ (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
+# define XXH_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+/*!XXH_ACCEPT_NULL_INPUT_POINTER :
+ * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
+ * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
+ * By default, this option is disabled. To enable it, uncomment below define :
+ */
+/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
+
+/*!XXH_FORCE_NATIVE_FORMAT :
+ * By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
+ * Results are therefore identical for little-endian and big-endian CPU.
+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+ * Should endian-independance be of no importance for your application, you may set the #define below to 1,
+ * to improve speed for Big-endian CPU.
+ * This option has no impact on Little_Endian CPU.
+ */
+#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
+# define XXH_FORCE_NATIVE_FORMAT 0
+#endif
+
+/*!XXH_FORCE_ALIGN_CHECK :
+ * This is a minor performance trick, only useful with lots of very small keys.
+ * It means : check for aligned/unaligned input.
+ * The check costs one initial branch per hash; set to 0 when the input data
+ * is guaranteed to be aligned.
+ */
+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
+# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+# define XXH_FORCE_ALIGN_CHECK 0
+# else
+# define XXH_FORCE_ALIGN_CHECK 1
+# endif
+#endif
+
+
+/* *************************************
+* Includes & Memory related functions
+***************************************/
+/* Modify the local functions below should you wish to use some other memory routines */
+/* for malloc(), free() */
+#include <stdlib.h>
+#include <stddef.h> /* size_t */
+static void* XXH_malloc(size_t s) { return malloc(s); }
+static void XXH_free (void* p) { free(p); }
+/* for memcpy() */
+#include <string.h>
+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+
+#ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY
+#endif
+#include "xxhash.h"
+
+
+/* *************************************
+* Compiler Specific Options
+***************************************/
+#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define INLINE_KEYWORD inline
+#else
+# define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__)
+# define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define FORCE_INLINE_ATTR __forceinline
+#else
+# define FORCE_INLINE_ATTR
+#endif
+
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* *************************************
+* Basic Types
+***************************************/
+#ifndef MEM_MODULE
+# define MEM_MODULE
+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+# else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
+# endif
+#endif
+
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign;
+
+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
+static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
+
+#else
+
+/* portable and safe solution. Generally efficient.
+ * see : http://stackoverflow.com/a/32095106/646947
+ */
+
+static U32 XXH_read32(const void* memPtr)
+{
+ U32 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+static U64 XXH_read64(const void* memPtr)
+{
+ U64 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+
+/* ****************************************
+* Compiler-specific Functions and Macros
+******************************************/
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
+#if defined(_MSC_VER)
+# define XXH_rotl32(x,r) _rotl(x,r)
+# define XXH_rotl64(x,r) _rotl64(x,r)
+#else
+# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
+#endif
+
+#if defined(_MSC_VER) /* Visual Studio */
+# define XXH_swap32 _byteswap_ulong
+# define XXH_swap64 _byteswap_uint64
+#elif GCC_VERSION >= 403
+# define XXH_swap32 __builtin_bswap32
+# define XXH_swap64 __builtin_bswap64
+#else
+static U32 XXH_swap32 (U32 x)
+{
+ return ((x << 24) & 0xff000000 ) |
+ ((x << 8) & 0x00ff0000 ) |
+ ((x >> 8) & 0x0000ff00 ) |
+ ((x >> 24) & 0x000000ff );
+}
+static U64 XXH_swap64 (U64 x)
+{
+ return ((x << 56) & 0xff00000000000000ULL) |
+ ((x << 40) & 0x00ff000000000000ULL) |
+ ((x << 24) & 0x0000ff0000000000ULL) |
+ ((x << 8) & 0x000000ff00000000ULL) |
+ ((x >> 8) & 0x00000000ff000000ULL) |
+ ((x >> 24) & 0x0000000000ff0000ULL) |
+ ((x >> 40) & 0x000000000000ff00ULL) |
+ ((x >> 56) & 0x00000000000000ffULL);
+}
+#endif
+
+
+/* *************************************
+* Architecture Macros
+***************************************/
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
+/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
+#ifndef XXH_CPU_LITTLE_ENDIAN
+ static const int g_one = 1;
+# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
+#endif
+
+
+/* ***************************
+* Memory reads
+*****************************/
+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE32_align(ptr, endian, XXH_unaligned);
+}
+
+static U32 XXH_readBE32(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE64_align(ptr, endian, XXH_unaligned);
+}
+
+static U64 XXH_readBE64(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+}
+
+
+/* *************************************
+* Macros
+***************************************/
+#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
+
+
+/* *************************************
+* Constants
+***************************************/
+static const U32 PRIME32_1 = 2654435761U;
+static const U32 PRIME32_2 = 2246822519U;
+static const U32 PRIME32_3 = 3266489917U;
+static const U32 PRIME32_4 = 668265263U;
+static const U32 PRIME32_5 = 374761393U;
+
+static const U64 PRIME64_1 = 11400714785074694791ULL;
+static const U64 PRIME64_2 = 14029467366897019727ULL;
+static const U64 PRIME64_3 = 1609587929392839161ULL;
+static const U64 PRIME64_4 = 9650029242287828579ULL;
+static const U64 PRIME64_5 = 2870177450012600261ULL;
+
+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
+
+
+/* **************************
+* Utils
+****************************/
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+
+/* ***************************
+* Simple Hash Functions
+*****************************/
+
+static U32 XXH32_round(U32 seed, U32 input)
+{
+ seed += input * PRIME32_2;
+ seed = XXH_rotl32(seed, 13);
+ seed *= PRIME32_1;
+ return seed;
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* bEnd = p + len;
+ U32 h32;
+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)16;
+ }
+#endif
+
+ if (len>=16) {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = seed + PRIME32_1 + PRIME32_2;
+ U32 v2 = seed + PRIME32_2;
+ U32 v3 = seed + 0;
+ U32 v4 = seed - PRIME32_1;
+
+ do {
+ v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
+ v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
+ v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
+ v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
+ } while (p<=limit);
+
+ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+ } else {
+ h32 = seed + PRIME32_5;
+ }
+
+ h32 += (U32) len;
+
+ while (p+4<=bEnd) {
+ h32 += XXH_get32bits(p) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH32_CREATESTATE_STATIC(state);
+ XXH32_reset(state, seed);
+ XXH32_update(state, input, len);
+ return XXH32_digest(state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+static U64 XXH64_round(U64 acc, U64 input)
+{
+ acc += input * PRIME64_2;
+ acc = XXH_rotl64(acc, 31);
+ acc *= PRIME64_1;
+ return acc;
+}
+
+static U64 XXH64_mergeRound(U64 acc, U64 val)
+{
+ val = XXH64_round(0, val);
+ acc ^= val;
+ acc = acc * PRIME64_1 + PRIME64_4;
+ return acc;
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+ U64 h64;
+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)32;
+ }
+#endif
+
+ if (len>=32) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = seed + PRIME64_1 + PRIME64_2;
+ U64 v2 = seed + PRIME64_2;
+ U64 v3 = seed + 0;
+ U64 v4 = seed - PRIME64_1;
+
+ do {
+ v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
+ v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
+ v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
+ v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
+ } while (p<=limit);
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+
+ } else {
+ h64 = seed + PRIME64_5;
+ }
+
+ h64 += (U64) len;
+
+ while (p+8<=bEnd) {
+ U64 const k1 = XXH64_round(0, XXH_get64bits(p));
+ h64 ^= k1;
+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+ p+=8;
+ }
+
+ if (p+4<=bEnd) {
+ h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h64 ^= (*p) * PRIME64_5;
+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+ p++;
+ }
+
+ h64 ^= h64 >> 33;
+ h64 *= PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= PRIME64_3;
+ h64 ^= h64 >> 32;
+
+ return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH64_CREATESTATE_STATIC(state);
+ XXH64_reset(state, seed);
+ XXH64_update(state, input, len);
+ return XXH64_digest(state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+/* **************************************************
+* Advanced Hash Functions
+****************************************************/
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
+{
+ return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
+{
+ return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+
+/*** Hash feed ***/
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
+{
+ XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
+ state.v1 = seed + PRIME32_1 + PRIME32_2;
+ state.v2 = seed + PRIME32_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME32_1;
+ memcpy(statePtr, &state, sizeof(state));
+ return XXH_OK;
+}
+
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
+{
+ XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
+ state.v1 = seed + PRIME64_1 + PRIME64_2;
+ state.v2 = seed + PRIME64_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME64_1;
+ memcpy(statePtr, &state, sizeof(state));
+ return XXH_OK;
+}
+
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (input==NULL) return XXH_ERROR;
+#endif
+
+ state->total_len_32 += (unsigned)len;
+ state->large_len |= (len>=16) | (state->total_len_32>=16);
+
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
+ state->memsize += (unsigned)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* some data left from previous update */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
+ { const U32* p32 = state->mem32;
+ state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
+ state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
+ state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
+ state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
+ }
+ p += 16-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p <= bEnd-16) {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = state->v1;
+ U32 v2 = state->v2;
+ U32 v3 = state->v3;
+ U32 v4 = state->v4;
+
+ do {
+ v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
+ v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
+ v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
+ v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
+{
+ const BYTE * p = (const BYTE*)state->mem32;
+ const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
+ U32 h32;
+
+ if (state->large_len) {
+ h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+ } else {
+ h32 = state->v3 /* == seed */ + PRIME32_5;
+ }
+
+ h32 += state->total_len_32;
+
+ while (p+4<=bEnd) {
+ h32 += XXH_readLE32(p, endian) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH32_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+
+/* **** XXH64 **** */
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (input==NULL) return XXH_ERROR;
+#endif
+
+ state->total_len += len;
+
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
+ state->memsize += (U32)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* tmp buffer is full */
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
+ state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
+ state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
+ state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
+ state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
+ p += 32-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p+32 <= bEnd) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = state->v1;
+ U64 v2 = state->v2;
+ U64 v3 = state->v3;
+ U64 v4 = state->v4;
+
+ do {
+ v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
+ v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
+ v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
+ v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
+{
+ const BYTE * p = (const BYTE*)state->mem64;
+ const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
+ U64 h64;
+
+ if (state->total_len >= 32) {
+ U64 const v1 = state->v1;
+ U64 const v2 = state->v2;
+ U64 const v3 = state->v3;
+ U64 const v4 = state->v4;
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+ } else {
+ h64 = state->v3 + PRIME64_5;
+ }
+
+ h64 += (U64) state->total_len;
+
+ while (p+8<=bEnd) {
+ U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
+ h64 ^= k1;
+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+ p+=8;
+ }
+
+ if (p+4<=bEnd) {
+ h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h64 ^= (*p) * PRIME64_5;
+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+ p++;
+ }
+
+ h64 ^= h64 >> 33;
+ h64 *= PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= PRIME64_3;
+ h64 ^= h64 >> 32;
+
+ return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH64_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+/* **************************
+* Canonical representation
+****************************/
+
+/*! Default XXH result types are basic unsigned 32 and 64 bits.
+* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
+* These functions allow transformation of hash result into and from its canonical format.
+* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
+*/
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
+{
+ return XXH_readBE32(src);
+}
+
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
+{
+ return XXH_readBE64(src);
+}
diff --git a/Utilities/cmzstd/lib/common/xxhash.h b/Utilities/cmzstd/lib/common/xxhash.h
new file mode 100644
index 000000000..9bad1f59f
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/xxhash.h
@@ -0,0 +1,305 @@
+/*
+ xxHash - Extremely Fast Hash algorithm
+ Header File
+ Copyright (C) 2012-2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+/* Notice extracted from xxHash homepage :
+
+xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+
+Name Speed Q.Score Author
+xxHash 5.4 GB/s 10
+CrapWow 3.2 GB/s 2 Andrew
+MumurHash 3a 2.7 GB/s 10 Austin Appleby
+SpookyHash 2.0 GB/s 10 Bob Jenkins
+SBox 1.4 GB/s 9 Bret Mulvey
+Lookup3 1.2 GB/s 9 Bob Jenkins
+SuperFastHash 1.2 GB/s 1 Paul Hsieh
+CityHash64 1.05 GB/s 10 Pike & Alakuijala
+FNV 0.55 GB/s 5 Fowler, Noll, Vo
+CRC32 0.43 GB/s 9
+MD5-32 0.33 GB/s 10 Ronald L. Rivest
+SHA1-32 0.28 GB/s 10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+A 64-bits version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bits applications only.
+Name Speed on 64 bits Speed on 32 bits
+XXH64 13.8 GB/s 1.9 GB/s
+XXH32 6.8 GB/s 6.0 GB/s
+*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef XXHASH_H_5627135585666179
+#define XXHASH_H_5627135585666179 1
+
+
+/* ****************************
+* Definitions
+******************************/
+#include <stddef.h> /* size_t */
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+
+/* ****************************
+* API modifier
+******************************/
+/** XXH_PRIVATE_API
+* This is useful if you want to include xxhash functions in `static` mode
+* in order to inline them, and remove their symbol from the public list.
+* Methodology :
+* #define XXH_PRIVATE_API
+* #include "xxhash.h"
+* `xxhash.c` is automatically included.
+* It's not useful to compile and link it as a separate module anymore.
+*/
+#ifdef XXH_PRIVATE_API
+# ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY
+# endif
+# if defined(__GNUC__)
+# define XXH_PUBLIC_API static __inline __attribute__((unused))
+# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define XXH_PUBLIC_API static inline
+# elif defined(_MSC_VER)
+# define XXH_PUBLIC_API static __inline
+# else
+# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */
+# endif
+#else
+# define XXH_PUBLIC_API /* do nothing */
+#endif /* XXH_PRIVATE_API */
+
+/*!XXH_NAMESPACE, aka Namespace Emulation :
+
+If you want to include _and expose_ xxHash functions from within your own library,
+but also want to avoid symbol collisions with another library which also includes xxHash,
+
+you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
+with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
+
+Note that no change is required within the calling program as long as it includes `xxhash.h` :
+regular symbol name will be automatically translated by this header.
+*/
+#ifdef XXH_NAMESPACE
+# define XXH_CAT(A,B) A##B
+# define XXH_NAME2(A,B) XXH_CAT(A,B)
+# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+#endif
+
+
+/* *************************************
+* Version
+***************************************/
+#define XXH_VERSION_MAJOR 0
+#define XXH_VERSION_MINOR 6
+#define XXH_VERSION_RELEASE 2
+#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
+XXH_PUBLIC_API unsigned XXH_versionNumber (void);
+
+
+/* ****************************
+* Simple Hash Functions
+******************************/
+typedef unsigned int XXH32_hash_t;
+typedef unsigned long long XXH64_hash_t;
+
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
+
+/*!
+XXH32() :
+ Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
+ The memory between input & input+length must be valid (allocated and read-accessible).
+ "seed" can be used to alter the result predictably.
+ Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
+XXH64() :
+ Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
+ "seed" can be used to alter the result predictably.
+ This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
+*/
+
+
+/* ****************************
+* Streaming Hash Functions
+******************************/
+typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
+typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
+
+/*! State allocation, compatible with dynamic libraries */
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
+
+
+/* hash streaming */
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
+
+/*
+These functions generate the xxHash of an input provided in multiple segments.
+Note that, for small input, they are slower than single-call functions, due to state management.
+For small input, prefer `XXH32()` and `XXH64()` .
+
+XXH state must first be allocated, using XXH*_createState() .
+
+Start a new hash by initializing state with a seed, using XXH*_reset().
+
+Then, feed the hash state by calling XXH*_update() as many times as necessary.
+Obviously, input must be allocated and read accessible.
+The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
+
+Finally, a hash value can be produced anytime, by using XXH*_digest().
+This function returns the nn-bits hash as an int or long long.
+
+It's still possible to continue inserting input into the hash state after a digest,
+and generate some new hashes later on, by calling again XXH*_digest().
+
+When done, free XXH state space if it was allocated dynamically.
+*/
+
+
+/* **************************
+* Utils
+****************************/
+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */
+# define restrict /* disable restrict */
+#endif
+
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state);
+
+
+/* **************************
+* Canonical representation
+****************************/
+/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
+* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
+* These functions allow transformation of hash result into and from its canonical format.
+* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
+*/
+typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
+
+#endif /* XXHASH_H_5627135585666179 */
+
+
+
+/* ================================================================================================
+ This section contains definitions which are not guaranteed to remain stable.
+ They may change in future versions, becoming incompatible with a different version of the library.
+ They shall only be used with static linking.
+ Never use these definitions in association with dynamic linking !
+=================================================================================================== */
+#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345)
+#define XXH_STATIC_H_3543687687345
+
+/* These definitions are only meant to allow allocation of XXH state
+ statically, on stack, or in a struct for example.
+ Do not use members directly. */
+
+ struct XXH32_state_s {
+ unsigned total_len_32;
+ unsigned large_len;
+ unsigned v1;
+ unsigned v2;
+ unsigned v3;
+ unsigned v4;
+ unsigned mem32[4]; /* buffer defined as U32 for alignment */
+ unsigned memsize;
+ unsigned reserved; /* never read nor write, will be removed in a future version */
+ }; /* typedef'd to XXH32_state_t */
+
+ struct XXH64_state_s {
+ unsigned long long total_len;
+ unsigned long long v1;
+ unsigned long long v2;
+ unsigned long long v3;
+ unsigned long long v4;
+ unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
+ unsigned memsize;
+ unsigned reserved[2]; /* never read nor write, will be removed in a future version */
+ }; /* typedef'd to XXH64_state_t */
+
+
+# ifdef XXH_PRIVATE_API
+# include "xxhash.c" /* include xxhash functions as `static`, for inlining */
+# endif
+
+#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/zstd_common.c b/Utilities/cmzstd/lib/common/zstd_common.c
new file mode 100644
index 000000000..667f4a27f
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_common.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <stdlib.h> /* malloc, calloc, free */
+#include <string.h> /* memset */
+#include "error_private.h"
+#include "zstd_internal.h"
+
+
+/*-****************************************
+* Version
+******************************************/
+unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; }
+
+const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
+
+
+/*-****************************************
+* ZSTD Error Management
+******************************************/
+#undef ZSTD_isError /* defined within zstd_internal.h */
+/*! ZSTD_isError() :
+ * tells if a return value is an error code
+ * symbol is required for external callers */
+unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
+
+/*! ZSTD_getErrorName() :
+ * provides error code string from function result (useful for debugging) */
+const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+/*! ZSTD_getError() :
+ * convert a `size_t` function result into a proper ZSTD_errorCode enum */
+ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
+
+/*! ZSTD_getErrorString() :
+ * provides error code string from enum */
+const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
+
+
+
+/*=**************************************************************
+* Custom allocator
+****************************************************************/
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
+{
+ if (customMem.customAlloc)
+ return customMem.customAlloc(customMem.opaque, size);
+ return malloc(size);
+}
+
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem)
+{
+ if (customMem.customAlloc) {
+ /* calloc implemented as malloc+memset;
+ * not as efficient as calloc, but next best guess for custom malloc */
+ void* const ptr = customMem.customAlloc(customMem.opaque, size);
+ memset(ptr, 0, size);
+ return ptr;
+ }
+ return calloc(1, size);
+}
+
+void ZSTD_free(void* ptr, ZSTD_customMem customMem)
+{
+ if (ptr!=NULL) {
+ if (customMem.customFree)
+ customMem.customFree(customMem.opaque, ptr);
+ else
+ free(ptr);
+ }
+}
diff --git a/Utilities/cmzstd/lib/common/zstd_errors.h b/Utilities/cmzstd/lib/common/zstd_errors.h
new file mode 100644
index 000000000..92a343389
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_errors.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_ERRORS_H_398273423
+#define ZSTD_ERRORS_H_398273423
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*===== dependency =====*/
+#include <stddef.h> /* size_t */
+
+
+/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
+#ifndef ZSTDERRORLIB_VISIBILITY
+# if defined(__GNUC__) && (__GNUC__ >= 4)
+# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default")))
+# else
+# define ZSTDERRORLIB_VISIBILITY
+# endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
+#endif
+
+/*-*********************************************
+ * Error codes list
+ *-*********************************************
+ * Error codes _values_ are pinned down since v1.3.1 only.
+ * Therefore, don't rely on values if you may link to any version < v1.3.1.
+ *
+ * Only values < 100 are considered stable.
+ *
+ * note 1 : this API shall be used with static linking only.
+ * dynamic linking is not yet officially supported.
+ * note 2 : Prefer relying on the enum than on its value whenever possible
+ * This is the only supported way to use the error list < v1.3.1
+ * note 3 : ZSTD_isError() is always correct, whatever the library version.
+ **********************************************/
+typedef enum {
+ ZSTD_error_no_error = 0,
+ ZSTD_error_GENERIC = 1,
+ ZSTD_error_prefix_unknown = 10,
+ ZSTD_error_version_unsupported = 12,
+ ZSTD_error_frameParameter_unsupported = 14,
+ ZSTD_error_frameParameter_windowTooLarge = 16,
+ ZSTD_error_corruption_detected = 20,
+ ZSTD_error_checksum_wrong = 22,
+ ZSTD_error_dictionary_corrupted = 30,
+ ZSTD_error_dictionary_wrong = 32,
+ ZSTD_error_dictionaryCreation_failed = 34,
+ ZSTD_error_parameter_unsupported = 40,
+ ZSTD_error_parameter_outOfBound = 42,
+ ZSTD_error_tableLog_tooLarge = 44,
+ ZSTD_error_maxSymbolValue_tooLarge = 46,
+ ZSTD_error_maxSymbolValue_tooSmall = 48,
+ ZSTD_error_stage_wrong = 60,
+ ZSTD_error_init_missing = 62,
+ ZSTD_error_memory_allocation = 64,
+ ZSTD_error_workSpace_tooSmall= 66,
+ ZSTD_error_dstSize_tooSmall = 70,
+ ZSTD_error_srcSize_wrong = 72,
+ ZSTD_error_dstBuffer_null = 74,
+ /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
+ ZSTD_error_frameIndex_tooLarge = 100,
+ ZSTD_error_seekableIO = 102,
+ ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
+} ZSTD_ErrorCode;
+
+/*! ZSTD_getErrorCode() :
+ convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,
+ which can be used to compare with enum list published above */
+ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);
+ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_ERRORS_H_398273423 */
diff --git a/Utilities/cmzstd/lib/common/zstd_internal.h b/Utilities/cmzstd/lib/common/zstd_internal.h
new file mode 100644
index 000000000..edeb74b9c
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_internal.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_CCOMMON_H_MODULE
+#define ZSTD_CCOMMON_H_MODULE
+
+/* this module contains definitions which must be identical
+ * across compression, decompression and dictBuilder.
+ * It also contains a few functions useful to at least 2 of them
+ * and which benefit from being inlined */
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include "compiler.h"
+#include "mem.h"
+#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */
+#include "error_private.h"
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
+#endif
+#include "xxhash.h" /* XXH_reset, update, digest */
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* ---- static assert (debug) --- */
+#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
+#define ZSTD_isError ERR_isError /* for inlining */
+#define FSE_isError ERR_isError
+#define HUF_isError ERR_isError
+
+
+/*-*************************************
+* shared macros
+***************************************/
+#undef MIN
+#undef MAX
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */
+#define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); } /* check and send Error code */
+
+
+/*-*************************************
+* Common constants
+***************************************/
+#define ZSTD_OPT_NUM (1<<12)
+
+#define ZSTD_REP_NUM 3 /* number of repcodes */
+#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
+static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define BIT7 128
+#define BIT6 64
+#define BIT5 32
+#define BIT4 16
+#define BIT1 2
+#define BIT0 1
+
+#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
+static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
+static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
+
+#define ZSTD_FRAMEIDSIZE 4 /* magic number size */
+
+#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
+static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
+typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
+
+#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
+#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
+
+#define HufLog 12
+typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
+
+#define LONGNBSEQ 0x7F00
+
+#define MINMATCH 3
+
+#define Litbits 8
+#define MaxLit ((1<<Litbits) - 1)
+#define MaxML 52
+#define MaxLL 35
+#define DefaultMaxOff 28
+#define MaxOff 31
+#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
+#define MLFSELog 9
+#define LLFSELog 9
+#define OffFSELog 8
+#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
+
+static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 6, 7, 8, 9,10,11,12,
+ 13,14,15,16 };
+static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 2, 1, 1, 1, 1, 1,
+ -1,-1,-1,-1 };
+#define LL_DEFAULTNORMLOG 6 /* for static allocation */
+static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
+
+static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 7, 8, 9,10,11,
+ 12,13,14,15,16 };
+static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1,-1,-1,
+ -1,-1,-1,-1,-1 };
+#define ML_DEFAULTNORMLOG 6 /* for static allocation */
+static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
+
+static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ -1,-1,-1,-1,-1 };
+#define OF_DEFAULTNORMLOG 5 /* for static allocation */
+static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
+
+
+/*-*******************************************
+* Shared functions to include for inlining
+*********************************************/
+static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
+#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
+
+/*! ZSTD_wildcopy() :
+ * custom version of memcpy(), can overwrite up to WILDCOPY_OVERLENGTH bytes (if length==0) */
+#define WILDCOPY_OVERLENGTH 8
+MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
+{
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ BYTE* const oend = op + length;
+ do
+ COPY8(op, ip)
+ while (op < oend);
+}
+
+MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd) /* should be faster for decoding, but strangely, not verified on all platform */
+{
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ BYTE* const oend = (BYTE*)dstEnd;
+ do
+ COPY8(op, ip)
+ while (op < oend);
+}
+
+
+/*-*******************************************
+* Private declarations
+*********************************************/
+typedef struct seqDef_s {
+ U32 offset;
+ U16 litLength;
+ U16 matchLength;
+} seqDef;
+
+typedef struct {
+ seqDef* sequencesStart;
+ seqDef* sequences;
+ BYTE* litStart;
+ BYTE* lit;
+ BYTE* llCode;
+ BYTE* mlCode;
+ BYTE* ofCode;
+ size_t maxNbSeq;
+ size_t maxNbLit;
+ U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
+ U32 longLengthPos;
+} seqStore_t;
+
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
+
+/* custom memory allocation functions */
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
+void ZSTD_free(void* ptr, ZSTD_customMem customMem);
+
+
+MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
+{
+ assert(val != 0);
+ {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ _BitScanReverse(&r, val);
+ return (unsigned)r;
+# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
+ return 31 - __builtin_clz(val);
+# else /* Software version */
+ static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
+ U32 v = val;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return DeBruijnClz[(v * 0x07C4ACDDU) >> 27];
+# endif
+ }
+}
+
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ * do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */
+
+
+typedef struct {
+ blockType_e blockType;
+ U32 lastBlock;
+ U32 origSize;
+} blockProperties_t; /* declared here for decompress and fullbench */
+
+/*! ZSTD_getcBlockSize() :
+ * Provides the size of compressed block from block header `src` */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+ blockProperties_t* bpPtr);
+
+/*! ZSTD_decodeSeqHeaders() :
+ * decode sequence header from src */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+ const void* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_CCOMMON_H_MODULE */
diff --git a/Utilities/cmzstd/lib/compress/fse_compress.c b/Utilities/cmzstd/lib/compress/fse_compress.c
new file mode 100644
index 000000000..60f357bbd
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/fse_compress.c
@@ -0,0 +1,721 @@
+/* ******************************************************************
+ FSE : Finite State Entropy encoder
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memcpy, memset */
+#include "compiler.h"
+#include "mem.h" /* U32, U16, etc. */
+#include "debug.h" /* assert, DEBUGLOG */
+#include "hist.h" /* HIST_count_wksp */
+#include "bitstream.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+
+
+/* **************************************************************
+* Templates
+****************************************************************/
+/*
+ designed to be included
+ for type-specific functions (template emulation in C)
+ Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+# error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+# error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
+ * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize)
+{
+ U32 const tableSize = 1 << tableLog;
+ U32 const tableMask = tableSize - 1;
+ void* const ptr = ct;
+ U16* const tableU16 = ( (U16*) ptr) + 2;
+ void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
+ FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
+
+ FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
+ U32 highThreshold = tableSize-1;
+
+ /* CTable header */
+ if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
+ tableU16[-2] = (U16) tableLog;
+ tableU16[-1] = (U16) maxSymbolValue;
+ assert(tableLog < 16); /* required for threshold strategy to work */
+
+ /* For explanations on how to distribute symbol values over the table :
+ * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
+
+ #ifdef __clang_analyzer__
+ memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */
+ #endif
+
+ /* symbol start positions */
+ { U32 u;
+ cumul[0] = 0;
+ for (u=1; u <= maxSymbolValue+1; u++) {
+ if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
+ cumul[u] = cumul[u-1] + 1;
+ tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
+ } else {
+ cumul[u] = cumul[u-1] + normalizedCounter[u-1];
+ } }
+ cumul[maxSymbolValue+1] = tableSize+1;
+ }
+
+ /* Spread symbols */
+ { U32 position = 0;
+ U32 symbol;
+ for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+ int nbOccurences;
+ int const freq = normalizedCounter[symbol];
+ for (nbOccurences=0; nbOccurences<freq; nbOccurences++) {
+ tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
+ position = (position + step) & tableMask;
+ while (position > highThreshold)
+ position = (position + step) & tableMask; /* Low proba area */
+ } }
+
+ assert(position==0); /* Must have initialized all positions */
+ }
+
+ /* Build table */
+ { U32 u; for (u=0; u<tableSize; u++) {
+ FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
+ tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */
+ } }
+
+ /* Build Symbol Transformation Table */
+ { unsigned total = 0;
+ unsigned s;
+ for (s=0; s<=maxSymbolValue; s++) {
+ switch (normalizedCounter[s])
+ {
+ case 0:
+ /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
+ symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
+ break;
+
+ case -1:
+ case 1:
+ symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
+ symbolTT[s].deltaFindState = total - 1;
+ total ++;
+ break;
+ default :
+ {
+ U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
+ U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
+ symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
+ symbolTT[s].deltaFindState = total - normalizedCounter[s];
+ total += normalizedCounter[s];
+ } } } }
+
+#if 0 /* debug : symbol costs */
+ DEBUGLOG(5, "\n --- table statistics : ");
+ { U32 symbol;
+ for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+ DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f",
+ symbol, normalizedCounter[symbol],
+ FSE_getMaxNbBits(symbolTT, symbol),
+ (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */
+ return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+
+/*-**************************************************************
+* FSE NCount encoding
+****************************************************************/
+size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
+{
+ size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
+ return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
+}
+
+static size_t
+FSE_writeNCount_generic (void* header, size_t headerBufferSize,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+ unsigned writeIsSafe)
+{
+ BYTE* const ostart = (BYTE*) header;
+ BYTE* out = ostart;
+ BYTE* const oend = ostart + headerBufferSize;
+ int nbBits;
+ const int tableSize = 1 << tableLog;
+ int remaining;
+ int threshold;
+ U32 bitStream = 0;
+ int bitCount = 0;
+ unsigned symbol = 0;
+ unsigned const alphabetSize = maxSymbolValue + 1;
+ int previousIs0 = 0;
+
+ /* Table Size */
+ bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
+ bitCount += 4;
+
+ /* Init */
+ remaining = tableSize+1; /* +1 for extra accuracy */
+ threshold = tableSize;
+ nbBits = tableLog+1;
+
+ while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
+ if (previousIs0) {
+ unsigned start = symbol;
+ while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;
+ if (symbol == alphabetSize) break; /* incorrect distribution */
+ while (symbol >= start+24) {
+ start+=24;
+ bitStream += 0xFFFFU << bitCount;
+ if ((!writeIsSafe) && (out > oend-2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE) bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out+=2;
+ bitStream>>=16;
+ }
+ while (symbol >= start+3) {
+ start+=3;
+ bitStream += 3 << bitCount;
+ bitCount += 2;
+ }
+ bitStream += (symbol-start) << bitCount;
+ bitCount += 2;
+ if (bitCount>16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out += 2;
+ bitStream >>= 16;
+ bitCount -= 16;
+ } }
+ { int count = normalizedCounter[symbol++];
+ int const max = (2*threshold-1) - remaining;
+ remaining -= count < 0 ? -count : count;
+ count++; /* +1 for extra accuracy */
+ if (count>=threshold)
+ count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
+ bitStream += count << bitCount;
+ bitCount += nbBits;
+ bitCount -= (count<max);
+ previousIs0 = (count==1);
+ if (remaining<1) return ERROR(GENERIC);
+ while (remaining<threshold) { nbBits--; threshold>>=1; }
+ }
+ if (bitCount>16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out += 2;
+ bitStream >>= 16;
+ bitCount -= 16;
+ } }
+
+ if (remaining != 1)
+ return ERROR(GENERIC); /* incorrect normalized distribution */
+ assert(symbol <= alphabetSize);
+
+ /* flush remaining bitStream */
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out+= (bitCount+7) /8;
+
+ return (out-ostart);
+}
+
+
+size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */
+ if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
+
+ if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
+ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
+
+ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);
+}
+
+
+/*-**************************************************************
+* FSE Compression Code
+****************************************************************/
+
+FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
+{
+ size_t size;
+ if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
+ size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
+ return (FSE_CTable*)malloc(size);
+}
+
+void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
+
+/* provides the minimum logSize to safely represent a distribution */
+static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
+{
+ U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
+ U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
+ U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
+ assert(srcSize > 1); /* Not supported, RLE should be used instead */
+ return minBits;
+}
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
+{
+ U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
+ U32 tableLog = maxTableLog;
+ U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
+ assert(srcSize > 1); /* Not supported, RLE should be used instead */
+ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+ if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
+ if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
+ if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
+ if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
+ return tableLog;
+}
+
+unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
+}
+
+
+/* Secondary normalization method.
+ To be used when primary method fails. */
+
+static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
+{
+ short const NOT_YET_ASSIGNED = -2;
+ U32 s;
+ U32 distributed = 0;
+ U32 ToDistribute;
+
+ /* Init */
+ U32 const lowThreshold = (U32)(total >> tableLog);
+ U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
+
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (count[s] == 0) {
+ norm[s]=0;
+ continue;
+ }
+ if (count[s] <= lowThreshold) {
+ norm[s] = -1;
+ distributed++;
+ total -= count[s];
+ continue;
+ }
+ if (count[s] <= lowOne) {
+ norm[s] = 1;
+ distributed++;
+ total -= count[s];
+ continue;
+ }
+
+ norm[s]=NOT_YET_ASSIGNED;
+ }
+ ToDistribute = (1 << tableLog) - distributed;
+
+ if (ToDistribute == 0)
+ return 0;
+
+ if ((total / ToDistribute) > lowOne) {
+ /* risk of rounding to zero */
+ lowOne = (U32)((total * 3) / (ToDistribute * 2));
+ for (s=0; s<=maxSymbolValue; s++) {
+ if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
+ norm[s] = 1;
+ distributed++;
+ total -= count[s];
+ continue;
+ } }
+ ToDistribute = (1 << tableLog) - distributed;
+ }
+
+ if (distributed == maxSymbolValue+1) {
+ /* all values are pretty poor;
+ probably incompressible data (should have already been detected);
+ find max, then give all remaining points to max */
+ U32 maxV = 0, maxC = 0;
+ for (s=0; s<=maxSymbolValue; s++)
+ if (count[s] > maxC) { maxV=s; maxC=count[s]; }
+ norm[maxV] += (short)ToDistribute;
+ return 0;
+ }
+
+ if (total == 0) {
+ /* all of the symbols were low enough for the lowOne or lowThreshold */
+ for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
+ if (norm[s] > 0) { ToDistribute--; norm[s]++; }
+ return 0;
+ }
+
+ { U64 const vStepLog = 62 - tableLog;
+ U64 const mid = (1ULL << (vStepLog-1)) - 1;
+ U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */
+ U64 tmpTotal = mid;
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (norm[s]==NOT_YET_ASSIGNED) {
+ U64 const end = tmpTotal + (count[s] * rStep);
+ U32 const sStart = (U32)(tmpTotal >> vStepLog);
+ U32 const sEnd = (U32)(end >> vStepLog);
+ U32 const weight = sEnd - sStart;
+ if (weight < 1)
+ return ERROR(GENERIC);
+ norm[s] = (short)weight;
+ tmpTotal = end;
+ } } }
+
+ return 0;
+}
+
+
+size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
+ const unsigned* count, size_t total,
+ unsigned maxSymbolValue)
+{
+ /* Sanity checks */
+ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+ if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
+ if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
+
+ { static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
+ U64 const scale = 62 - tableLog;
+ U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
+ U64 const vStep = 1ULL<<(scale-20);
+ int stillToDistribute = 1<<tableLog;
+ unsigned s;
+ unsigned largest=0;
+ short largestP=0;
+ U32 lowThreshold = (U32)(total >> tableLog);
+
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (count[s] == total) return 0; /* rle special case */
+ if (count[s] == 0) { normalizedCounter[s]=0; continue; }
+ if (count[s] <= lowThreshold) {
+ normalizedCounter[s] = -1;
+ stillToDistribute--;
+ } else {
+ short proba = (short)((count[s]*step) >> scale);
+ if (proba<8) {
+ U64 restToBeat = vStep * rtbTable[proba];
+ proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
+ }
+ if (proba > largestP) { largestP=proba; largest=s; }
+ normalizedCounter[s] = proba;
+ stillToDistribute -= proba;
+ } }
+ if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
+ /* corner case, need another normalization method */
+ size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
+ if (FSE_isError(errorCode)) return errorCode;
+ }
+ else normalizedCounter[largest] += (short)stillToDistribute;
+ }
+
+#if 0
+ { /* Print Table (debug) */
+ U32 s;
+ U32 nTotal = 0;
+ for (s=0; s<=maxSymbolValue; s++)
+ RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
+ for (s=0; s<=maxSymbolValue; s++)
+ nTotal += abs(normalizedCounter[s]);
+ if (nTotal != (1U<<tableLog))
+ RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
+ getchar();
+ }
+#endif
+
+ return tableLog;
+}
+
+
+/* fake FSE_CTable, for raw (uncompressed) input */
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
+{
+ const unsigned tableSize = 1 << nbBits;
+ const unsigned tableMask = tableSize - 1;
+ const unsigned maxSymbolValue = tableMask;
+ void* const ptr = ct;
+ U16* const tableU16 = ( (U16*) ptr) + 2;
+ void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */
+ FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ unsigned s;
+
+ /* Sanity checks */
+ if (nbBits < 1) return ERROR(GENERIC); /* min size */
+
+ /* header */
+ tableU16[-2] = (U16) nbBits;
+ tableU16[-1] = (U16) maxSymbolValue;
+
+ /* Build table */
+ for (s=0; s<tableSize; s++)
+ tableU16[s] = (U16)(tableSize + s);
+
+ /* Build Symbol Transformation Table */
+ { const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
+ for (s=0; s<=maxSymbolValue; s++) {
+ symbolTT[s].deltaNbBits = deltaNbBits;
+ symbolTT[s].deltaFindState = s-1;
+ } }
+
+ return 0;
+}
+
+/* fake FSE_CTable, for rle input (always same symbol) */
+size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
+{
+ void* ptr = ct;
+ U16* tableU16 = ( (U16*) ptr) + 2;
+ void* FSCTptr = (U32*)ptr + 2;
+ FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
+
+ /* header */
+ tableU16[-2] = (U16) 0;
+ tableU16[-1] = (U16) symbolValue;
+
+ /* Build table */
+ tableU16[0] = 0;
+ tableU16[1] = 0; /* just in case */
+
+ /* Build Symbol Transformation Table */
+ symbolTT[symbolValue].deltaNbBits = 0;
+ symbolTT[symbolValue].deltaFindState = 0;
+
+ return 0;
+}
+
+
+static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const FSE_CTable* ct, const unsigned fast)
+{
+ const BYTE* const istart = (const BYTE*) src;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* ip=iend;
+
+ BIT_CStream_t bitC;
+ FSE_CState_t CState1, CState2;
+
+ /* init */
+ if (srcSize <= 2) return 0;
+ { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
+ if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
+
+#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
+
+ if (srcSize & 1) {
+ FSE_initCState2(&CState1, ct, *--ip);
+ FSE_initCState2(&CState2, ct, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ FSE_FLUSHBITS(&bitC);
+ } else {
+ FSE_initCState2(&CState2, ct, *--ip);
+ FSE_initCState2(&CState1, ct, *--ip);
+ }
+
+ /* join to mod 4 */
+ srcSize -= 2;
+ if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ FSE_FLUSHBITS(&bitC);
+ }
+
+ /* 2 or 4 encoding per loop */
+ while ( ip>istart ) {
+
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+
+ if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
+ FSE_FLUSHBITS(&bitC);
+
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+
+ if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ }
+
+ FSE_FLUSHBITS(&bitC);
+ }
+
+ FSE_flushCState(&bitC, &CState2);
+ FSE_flushCState(&bitC, &CState1);
+ return BIT_closeCStream(&bitC);
+}
+
+size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const FSE_CTable* ct)
+{
+ unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
+
+ if (fast)
+ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
+ else
+ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
+}
+
+
+size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
+
+#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
+#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` size must be `(1<<tableLog)`.
+ */
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const oend = ostart + dstSize;
+
+ unsigned count[FSE_MAX_SYMBOL_VALUE+1];
+ S16 norm[FSE_MAX_SYMBOL_VALUE+1];
+ FSE_CTable* CTable = (FSE_CTable*)workSpace;
+ size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
+ void* scratchBuffer = (void*)(CTable + CTableSize);
+ size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
+
+ /* init conditions */
+ if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
+ if (srcSize <= 1) return 0; /* Not compressible */
+ if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+ if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
+
+ /* Scan input and build symbol stats */
+ { CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );
+ if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
+ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
+ if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
+ }
+
+ tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
+ CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
+
+ /* Write table description header */
+ { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+ op += nc_err;
+ }
+
+ /* Compress */
+ CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
+ { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
+ if (cSize == 0) return 0; /* not enough space for compressed data */
+ op += cSize;
+ }
+
+ /* check compressibility */
+ if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
+
+ return op-ostart;
+}
+
+typedef struct {
+ FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
+ BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
+} fseWkspMax_t;
+
+size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
+{
+ fseWkspMax_t scratchBuffer;
+ DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+ return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
+}
+
+size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
+}
+
+
+#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/Utilities/cmzstd/lib/compress/hist.c b/Utilities/cmzstd/lib/compress/hist.c
new file mode 100644
index 000000000..45b7babc1
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/hist.c
@@ -0,0 +1,203 @@
+/* ******************************************************************
+ hist : Histogram functions
+ part of Finite State Entropy project
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* --- dependencies --- */
+#include "mem.h" /* U32, BYTE, etc. */
+#include "debug.h" /* assert, DEBUGLOG */
+#include "error_private.h" /* ERROR */
+#include "hist.h"
+
+
+/* --- Error management --- */
+unsigned HIST_isError(size_t code) { return ERR_isError(code); }
+
+/*-**************************************************************
+ * Histogram functions
+ ****************************************************************/
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize)
+{
+ const BYTE* ip = (const BYTE*)src;
+ const BYTE* const end = ip + srcSize;
+ unsigned maxSymbolValue = *maxSymbolValuePtr;
+ unsigned largestCount=0;
+
+ memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
+ if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
+
+ while (ip<end) {
+ assert(*ip <= maxSymbolValue);
+ count[*ip++]++;
+ }
+
+ while (!count[maxSymbolValue]) maxSymbolValue--;
+ *maxSymbolValuePtr = maxSymbolValue;
+
+ { U32 s;
+ for (s=0; s<=maxSymbolValue; s++)
+ if (count[s] > largestCount) largestCount = count[s];
+ }
+
+ return largestCount;
+}
+
+typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e;
+
+/* HIST_count_parallel_wksp() :
+ * store histogram into 4 intermediate tables, recombined at the end.
+ * this design makes better use of OoO cpus,
+ * and is noticeably faster when some values are heavily repeated.
+ * But it needs some additional workspace for intermediate tables.
+ * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
+ * @return : largest histogram frequency,
+ * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
+static size_t HIST_count_parallel_wksp(
+ unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ HIST_checkInput_e check,
+ U32* const workSpace)
+{
+ const BYTE* ip = (const BYTE*)source;
+ const BYTE* const iend = ip+sourceSize;
+ unsigned maxSymbolValue = *maxSymbolValuePtr;
+ unsigned max=0;
+ U32* const Counting1 = workSpace;
+ U32* const Counting2 = Counting1 + 256;
+ U32* const Counting3 = Counting2 + 256;
+ U32* const Counting4 = Counting3 + 256;
+
+ memset(workSpace, 0, 4*256*sizeof(unsigned));
+
+ /* safety checks */
+ if (!sourceSize) {
+ memset(count, 0, maxSymbolValue + 1);
+ *maxSymbolValuePtr = 0;
+ return 0;
+ }
+ if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
+
+ /* by stripes of 16 bytes */
+ { U32 cached = MEM_read32(ip); ip += 4;
+ while (ip < iend-15) {
+ U32 c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ }
+ ip-=4;
+ }
+
+ /* finish last symbols */
+ while (ip<iend) Counting1[*ip++]++;
+
+ if (check) { /* verify stats will fit into destination table */
+ U32 s; for (s=255; s>maxSymbolValue; s--) {
+ Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
+ if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
+ } }
+
+ { U32 s;
+ if (maxSymbolValue > 255) maxSymbolValue = 255;
+ for (s=0; s<=maxSymbolValue; s++) {
+ count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
+ if (count[s] > max) max = count[s];
+ } }
+
+ while (!count[maxSymbolValue]) maxSymbolValue--;
+ *maxSymbolValuePtr = maxSymbolValue;
+ return (size_t)max;
+}
+
+/* HIST_countFast_wksp() :
+ * Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ void* workSpace, size_t workSpaceSize)
+{
+ if (sourceSize < 1500) /* heuristic threshold */
+ return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
+ if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+ return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
+}
+
+/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize)
+{
+ unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+ return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
+}
+
+/* HIST_count_wksp() :
+ * Same as HIST_count(), but using an externally provided scratch buffer.
+ * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ void* workSpace, size_t workSpaceSize)
+{
+ if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+ if (*maxSymbolValuePtr < 255)
+ return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace);
+ *maxSymbolValuePtr = 255;
+ return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
+}
+
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize)
+{
+ unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+ return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters));
+}
diff --git a/Utilities/cmzstd/lib/compress/hist.h b/Utilities/cmzstd/lib/compress/hist.h
new file mode 100644
index 000000000..8b389358d
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/hist.h
@@ -0,0 +1,95 @@
+/* ******************************************************************
+ hist : Histogram functions
+ part of Finite State Entropy project
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* --- dependencies --- */
+#include <stddef.h> /* size_t */
+
+
+/* --- simple histogram functions --- */
+
+/*! HIST_count():
+ * Provides the precise count of each byte within a table 'count'.
+ * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
+ * Updates *maxSymbolValuePtr with actual largest symbol value detected.
+ * @return : count of the most frequent symbol (which isn't identified).
+ * or an error code, which can be tested using HIST_isError().
+ * note : if return == srcSize, there is only one symbol.
+ */
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
+
+unsigned HIST_isError(size_t code); /**< tells if a return value is an error code */
+
+
+/* --- advanced histogram functions --- */
+
+#define HIST_WKSP_SIZE_U32 1024
+#define HIST_WKSP_SIZE (HIST_WKSP_SIZE_U32 * sizeof(unsigned))
+/** HIST_count_wksp() :
+ * Same as HIST_count(), but using an externally provided scratch buffer.
+ * Benefit is this function will use very little stack space.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t workSpaceSize);
+
+/** HIST_countFast() :
+ * same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr.
+ * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr`
+ */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
+
+/** HIST_countFast_wksp() :
+ * Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t workSpaceSize);
+
+/*! HIST_count_simple() :
+ * Same as HIST_countFast(), this function is unsafe,
+ * and will segfault if any value within `src` is `> *maxSymbolValuePtr`.
+ * It is also a bit slower for large inputs.
+ * However, it does not need any additional memory (not even on stack).
+ * @return : count of the most frequent symbol.
+ * Note this function doesn't produce any error (i.e. it must succeed).
+ */
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
diff --git a/Utilities/cmzstd/lib/compress/huf_compress.c b/Utilities/cmzstd/lib/compress/huf_compress.c
new file mode 100644
index 000000000..f074f1e0a
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/huf_compress.c
@@ -0,0 +1,798 @@
+/* ******************************************************************
+ Huffman encoder, part of New Generation Entropy library
+ Copyright (C) 2013-2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* **************************************************************
+* Compiler specifics
+****************************************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <string.h> /* memcpy, memset */
+#include <stdio.h> /* printf (debug) */
+#include "compiler.h"
+#include "bitstream.h"
+#include "hist.h"
+#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
+#include "fse.h" /* header compression */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+#define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
+#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
+#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
+
+
+/* **************************************************************
+* Utils
+****************************************************************/
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
+}
+
+
+/* *******************************************************
+* HUF : Huffman block compression
+*********************************************************/
+/* HUF_compressWeights() :
+ * Same as FSE_compress(), but dedicated to huff0's weights compression.
+ * The use case needs much less stack memory.
+ * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
+ */
+#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
+static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const oend = ostart + dstSize;
+
+ unsigned maxSymbolValue = HUF_TABLELOG_MAX;
+ U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
+
+ FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
+ BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
+
+ unsigned count[HUF_TABLELOG_MAX+1];
+ S16 norm[HUF_TABLELOG_MAX+1];
+
+ /* init conditions */
+ if (wtSize <= 1) return 0; /* Not compressible */
+
+ /* Scan input and build symbol stats */
+ { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
+ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
+ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
+ }
+
+ tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
+ CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
+
+ /* Write table description header */
+ { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+ op += hSize;
+ }
+
+ /* Compress */
+ CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
+ { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );
+ if (cSize == 0) return 0; /* not enough space for compressed data */
+ op += cSize;
+ }
+
+ return op-ostart;
+}
+
+
+struct HUF_CElt_s {
+ U16 val;
+ BYTE nbBits;
+}; /* typedef'd to HUF_CElt within "huf.h" */
+
+/*! HUF_writeCTable() :
+ `CTable` : Huffman tree to save, using huf representation.
+ @return : size of saved CTable */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize,
+ const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
+{
+ BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
+ BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
+ BYTE* op = (BYTE*)dst;
+ U32 n;
+
+ /* check conditions */
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+
+ /* convert to weight */
+ bitsToWeight[0] = 0;
+ for (n=1; n<huffLog+1; n++)
+ bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
+ for (n=0; n<maxSymbolValue; n++)
+ huffWeight[n] = bitsToWeight[CTable[n].nbBits];
+
+ /* attempt weights compression by FSE */
+ { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
+ if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
+ op[0] = (BYTE)hSize;
+ return hSize+1;
+ } }
+
+ /* write raw values as 4-bits (max : 15) */
+ if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
+ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
+ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
+ huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
+ for (n=0; n<maxSymbolValue; n+=2)
+ op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
+ return ((maxSymbolValue+1)/2) + 1;
+}
+
+
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize)
+{
+ BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
+ U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
+ U32 tableLog = 0;
+ U32 nbSymbols = 0;
+
+ /* get symbol weights */
+ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
+
+ /* check result */
+ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
+
+ /* Prepare base value per rank */
+ { U32 n, nextRankStart = 0;
+ for (n=1; n<=tableLog; n++) {
+ U32 current = nextRankStart;
+ nextRankStart += (rankVal[n] << (n-1));
+ rankVal[n] = current;
+ } }
+
+ /* fill nbBits */
+ { U32 n; for (n=0; n<nbSymbols; n++) {
+ const U32 w = huffWeight[n];
+ CTable[n].nbBits = (BYTE)(tableLog + 1 - w);
+ } }
+
+ /* fill val */
+ { U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */
+ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
+ { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
+ /* determine stating value per rank */
+ valPerRank[tableLog+1] = 0; /* for w==0 */
+ { U16 min = 0;
+ U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
+ valPerRank[n] = min; /* get starting value within each rank */
+ min += nbPerRank[n];
+ min >>= 1;
+ } }
+ /* assign value within rank, symbol order */
+ { U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
+ }
+
+ *maxSymbolValuePtr = nbSymbols - 1;
+ return readSize;
+}
+
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue)
+{
+ const HUF_CElt* table = (const HUF_CElt*)symbolTable;
+ assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
+ return table[symbolValue].nbBits;
+}
+
+
+typedef struct nodeElt_s {
+ U32 count;
+ U16 parent;
+ BYTE byte;
+ BYTE nbBits;
+} nodeElt;
+
+static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
+{
+ const U32 largestBits = huffNode[lastNonNull].nbBits;
+ if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
+
+ /* there are several too large elements (at least >= 2) */
+ { int totalCost = 0;
+ const U32 baseCost = 1 << (largestBits - maxNbBits);
+ U32 n = lastNonNull;
+
+ while (huffNode[n].nbBits > maxNbBits) {
+ totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
+ huffNode[n].nbBits = (BYTE)maxNbBits;
+ n --;
+ } /* n stops at huffNode[n].nbBits <= maxNbBits */
+ while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
+
+ /* renorm totalCost */
+ totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
+
+ /* repay normalized cost */
+ { U32 const noSymbol = 0xF0F0F0F0;
+ U32 rankLast[HUF_TABLELOG_MAX+2];
+ int pos;
+
+ /* Get pos of last (smallest) symbol per rank */
+ memset(rankLast, 0xF0, sizeof(rankLast));
+ { U32 currentNbBits = maxNbBits;
+ for (pos=n ; pos >= 0; pos--) {
+ if (huffNode[pos].nbBits >= currentNbBits) continue;
+ currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
+ rankLast[maxNbBits-currentNbBits] = pos;
+ } }
+
+ while (totalCost > 0) {
+ U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
+ for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
+ U32 highPos = rankLast[nBitsToDecrease];
+ U32 lowPos = rankLast[nBitsToDecrease-1];
+ if (highPos == noSymbol) continue;
+ if (lowPos == noSymbol) break;
+ { U32 const highTotal = huffNode[highPos].count;
+ U32 const lowTotal = 2 * huffNode[lowPos].count;
+ if (highTotal <= lowTotal) break;
+ } }
+ /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
+ /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
+ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
+ nBitsToDecrease ++;
+ totalCost -= 1 << (nBitsToDecrease-1);
+ if (rankLast[nBitsToDecrease-1] == noSymbol)
+ rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
+ huffNode[rankLast[nBitsToDecrease]].nbBits ++;
+ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
+ rankLast[nBitsToDecrease] = noSymbol;
+ else {
+ rankLast[nBitsToDecrease]--;
+ if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
+ rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
+ } } /* while (totalCost > 0) */
+
+ while (totalCost < 0) { /* Sometimes, cost correction overshoot */
+ if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+ while (huffNode[n].nbBits == maxNbBits) n--;
+ huffNode[n+1].nbBits--;
+ rankLast[1] = n+1;
+ totalCost++;
+ continue;
+ }
+ huffNode[ rankLast[1] + 1 ].nbBits--;
+ rankLast[1]++;
+ totalCost ++;
+ } } } /* there are several too large elements (at least >= 2) */
+
+ return maxNbBits;
+}
+
+
+typedef struct {
+ U32 base;
+ U32 current;
+} rankPos;
+
+static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue)
+{
+ rankPos rank[32];
+ U32 n;
+
+ memset(rank, 0, sizeof(rank));
+ for (n=0; n<=maxSymbolValue; n++) {
+ U32 r = BIT_highbit32(count[n] + 1);
+ rank[r].base ++;
+ }
+ for (n=30; n>0; n--) rank[n-1].base += rank[n].base;
+ for (n=0; n<32; n++) rank[n].current = rank[n].base;
+ for (n=0; n<=maxSymbolValue; n++) {
+ U32 const c = count[n];
+ U32 const r = BIT_highbit32(c+1) + 1;
+ U32 pos = rank[r].current++;
+ while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) {
+ huffNode[pos] = huffNode[pos-1];
+ pos--;
+ }
+ huffNode[pos].count = c;
+ huffNode[pos].byte = (BYTE)n;
+ }
+}
+
+
+/** HUF_buildCTable_wksp() :
+ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of HUF_CTABLE_WORKSPACE_SIZE_U32 unsigned.
+ */
+#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
+typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
+size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+{
+ nodeElt* const huffNode0 = (nodeElt*)workSpace;
+ nodeElt* const huffNode = huffNode0+1;
+ U32 n, nonNullRank;
+ int lowS, lowN;
+ U16 nodeNb = STARTNODE;
+ U32 nodeRoot;
+
+ /* safety checks */
+ if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (wkspSize < sizeof(huffNodeTable)) return ERROR(workSpace_tooSmall);
+ if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+ memset(huffNode0, 0, sizeof(huffNodeTable));
+
+ /* sort, decreasing order */
+ HUF_sort(huffNode, count, maxSymbolValue);
+
+ /* init for parents */
+ nonNullRank = maxSymbolValue;
+ while(huffNode[nonNullRank].count == 0) nonNullRank--;
+ lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
+ huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
+ huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb;
+ nodeNb++; lowS-=2;
+ for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
+ huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
+
+ /* create parents */
+ while (nodeNb <= nodeRoot) {
+ U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+ U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+ huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
+ huffNode[n1].parent = huffNode[n2].parent = nodeNb;
+ nodeNb++;
+ }
+
+ /* distribute weights (unlimited tree height) */
+ huffNode[nodeRoot].nbBits = 0;
+ for (n=nodeRoot-1; n>=STARTNODE; n--)
+ huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+ for (n=0; n<=nonNullRank; n++)
+ huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+
+ /* enforce maxTableLog */
+ maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
+
+ /* fill result into tree (val, nbBits) */
+ { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
+ U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
+ if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
+ for (n=0; n<=nonNullRank; n++)
+ nbPerRank[huffNode[n].nbBits]++;
+ /* determine stating value per rank */
+ { U16 min = 0;
+ for (n=maxNbBits; n>0; n--) {
+ valPerRank[n] = min; /* get starting value within each rank */
+ min += nbPerRank[n];
+ min >>= 1;
+ } }
+ for (n=0; n<=maxSymbolValue; n++)
+ tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
+ for (n=0; n<=maxSymbolValue; n++)
+ tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
+ }
+
+ return maxNbBits;
+}
+
+/** HUF_buildCTable() :
+ * @return : maxNbBits
+ * Note : count is used before tree is written, so they can safely overlap
+ */
+size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
+{
+ huffNodeTable nodeTable;
+ return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable));
+}
+
+static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
+{
+ size_t nbBits = 0;
+ int s;
+ for (s = 0; s <= (int)maxSymbolValue; ++s) {
+ nbBits += CTable[s].nbBits * count[s];
+ }
+ return nbBits >> 3;
+}
+
+static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
+ int bad = 0;
+ int s;
+ for (s = 0; s <= (int)maxSymbolValue; ++s) {
+ bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
+ }
+ return !bad;
+}
+
+size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
+
+FORCE_INLINE_TEMPLATE void
+HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
+{
+ BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
+}
+
+#define HUF_FLUSHBITS(s) BIT_flushBits(s)
+
+#define HUF_FLUSHBITS_1(stream) \
+ if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
+
+#define HUF_FLUSHBITS_2(stream) \
+ if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ const BYTE* ip = (const BYTE*) src;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+ size_t n;
+ BIT_CStream_t bitC;
+
+ /* init */
+ if (dstSize < 8) return 0; /* not enough space to compress */
+ { size_t const initErr = BIT_initCStream(&bitC, op, oend-op);
+ if (HUF_isError(initErr)) return 0; }
+
+ n = srcSize & ~3; /* join to mod 4 */
+ switch (srcSize & 3)
+ {
+ case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
+ HUF_FLUSHBITS_2(&bitC);
+ /* fall-through */
+ case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ /* fall-through */
+ case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
+ HUF_FLUSHBITS(&bitC);
+ /* fall-through */
+ case 0 : /* fall-through */
+ default: break;
+ }
+
+ for (; n>0; n-=4) { /* note : n&3==0 at this stage */
+ HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
+ HUF_FLUSHBITS_2(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
+ HUF_FLUSHBITS(&bitC);
+ }
+
+ return BIT_closeCStream(&bitC);
+}
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, const int bmi2)
+{
+ if (bmi2) {
+ return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
+ }
+ return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
+}
+
+#else
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, const int bmi2)
+{
+ (void)bmi2;
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+#endif
+
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+
+static size_t
+HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, int bmi2)
+{
+ size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* const iend = ip + srcSize;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+
+ if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
+ if (srcSize < 12) return 0; /* no saving possible : too small input */
+ op += 6; /* jumpTable */
+
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart+2, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart+4, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, iend-ip, CTable, bmi2) );
+ if (cSize==0) return 0;
+ op += cSize;
+ }
+
+ return op-ostart;
+}
+
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+ return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
+
+static size_t HUF_compressCTable_internal(
+ BYTE* const ostart, BYTE* op, BYTE* const oend,
+ const void* src, size_t srcSize,
+ HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2)
+{
+ size_t const cSize = (nbStreams==HUF_singleStream) ?
+ HUF_compress1X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2) :
+ HUF_compress4X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2);
+ if (HUF_isError(cSize)) { return cSize; }
+ if (cSize==0) { return 0; } /* uncompressible */
+ op += cSize;
+ /* check compressibility */
+ if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
+ return op-ostart;
+}
+
+typedef struct {
+ unsigned count[HUF_SYMBOLVALUE_MAX + 1];
+ HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
+ huffNodeTable nodeTable;
+} HUF_compress_tables_t;
+
+/* HUF_compress_internal() :
+ * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+static size_t
+HUF_compress_internal (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ HUF_nbStreams_e nbStreams,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
+ const int bmi2)
+{
+ HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+
+ /* checks & inits */
+ if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall);
+ if (!srcSize) return 0; /* Uncompressed */
+ if (!dstSize) return 0; /* cannot fit anything within dst budget */
+ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
+ if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+ if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+ if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
+
+ /* Heuristic : If old table is valid, use it for small inputs */
+ if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ }
+
+ /* Scan input and build symbol stats */
+ { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) );
+ if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
+ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
+ }
+
+ /* Check validity of previous table */
+ if ( repeat
+ && *repeat == HUF_repeat_check
+ && !HUF_validateCTable(oldHufTable, table->count, maxSymbolValue)) {
+ *repeat = HUF_repeat_none;
+ }
+ /* Heuristic : use existing table for small inputs */
+ if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ }
+
+ /* Build Huffman Tree */
+ huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+ { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
+ maxSymbolValue, huffLog,
+ table->nodeTable, sizeof(table->nodeTable));
+ CHECK_F(maxBits);
+ huffLog = (U32)maxBits;
+ /* Zero unused symbols in CTable, so we can check it for validity */
+ memset(table->CTable + (maxSymbolValue + 1), 0,
+ sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
+ }
+
+ /* Write table description header */
+ { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
+ /* Check if using previous huffman table is beneficial */
+ if (repeat && *repeat != HUF_repeat_none) {
+ size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
+ size_t const newSize = HUF_estimateCompressedSize(table->CTable, table->count, maxSymbolValue);
+ if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ } }
+
+ /* Use the new huffman table */
+ if (hSize + 12ul >= srcSize) { return 0; }
+ op += hSize;
+ if (repeat) { *repeat = HUF_repeat_none; }
+ if (oldHufTable)
+ memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */
+ }
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, table->CTable, bmi2);
+}
+
+
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_singleStream,
+ workSpace, wkspSize,
+ NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_singleStream,
+ workSpace, wkspSize, hufTable,
+ repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress1X (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog)
+{
+ unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+ return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * provide workspace to generate compression tables */
+size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_fourStreams,
+ workSpace, wkspSize,
+ NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * re-use an existing huffman compression table */
+size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_fourStreams,
+ workSpace, wkspSize,
+ hufTable, repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress2 (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog)
+{
+ unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+ return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
+{
+ return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_compress.c b/Utilities/cmzstd/lib/compress/zstd_compress.c
new file mode 100644
index 000000000..c2c9d3bc5
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_compress.c
@@ -0,0 +1,4290 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <limits.h> /* INT_MAX */
+#include <string.h> /* memset */
+#include "cpu.h"
+#include "mem.h"
+#include "hist.h" /* HIST_countFast_wksp */
+#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_compress_internal.h"
+#include "zstd_fast.h"
+#include "zstd_double_fast.h"
+#include "zstd_lazy.h"
+#include "zstd_opt.h"
+#include "zstd_ldm.h"
+
+
+/*-*************************************
+* Helper functions
+***************************************/
+size_t ZSTD_compressBound(size_t srcSize) {
+ return ZSTD_COMPRESSBOUND(srcSize);
+}
+
+
+/*-*************************************
+* Context memory management
+***************************************/
+struct ZSTD_CDict_s {
+ void* dictBuffer;
+ const void* dictContent;
+ size_t dictContentSize;
+ void* workspace;
+ size_t workspaceSize;
+ ZSTD_matchState_t matchState;
+ ZSTD_compressedBlockState_t cBlockState;
+ ZSTD_customMem customMem;
+ U32 dictID;
+}; /* typedef'd to ZSTD_CDict within "zstd.h" */
+
+ZSTD_CCtx* ZSTD_createCCtx(void)
+{
+ return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
+}
+
+static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
+{
+ assert(cctx != NULL);
+ memset(cctx, 0, sizeof(*cctx));
+ cctx->customMem = memManager;
+ cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
+ assert(!ZSTD_isError(err));
+ (void)err;
+ }
+}
+
+ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
+{
+ ZSTD_STATIC_ASSERT(zcss_init==0);
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+ { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
+ if (!cctx) return NULL;
+ ZSTD_initCCtx(cctx, customMem);
+ return cctx;
+ }
+}
+
+ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
+{
+ ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
+ if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
+ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
+ memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
+ cctx->staticSize = workspaceSize;
+ cctx->workSpace = (void*)(cctx+1);
+ cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
+
+ /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
+ if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL;
+ assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
+ cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
+ cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
+ {
+ void* const ptr = cctx->blockState.nextCBlock + 1;
+ cctx->entropyWorkspace = (U32*)ptr;
+ }
+ cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ return cctx;
+}
+
+static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
+{
+ assert(cctx != NULL);
+ assert(cctx->staticSize == 0);
+ ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
+ ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
+#ifdef ZSTD_MULTITHREAD
+ ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
+#endif
+}
+
+size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
+{
+ if (cctx==NULL) return 0; /* support free on NULL */
+ if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
+ ZSTD_freeCCtxContent(cctx);
+ ZSTD_free(cctx, cctx->customMem);
+ return 0;
+}
+
+
+static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ return ZSTDMT_sizeof_CCtx(cctx->mtctx);
+#else
+ (void)cctx;
+ return 0;
+#endif
+}
+
+
+size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
+{
+ if (cctx==NULL) return 0; /* support sizeof on NULL */
+ return sizeof(*cctx) + cctx->workSpaceSize
+ + ZSTD_sizeof_CDict(cctx->cdictLocal)
+ + ZSTD_sizeof_mtctx(cctx);
+}
+
+size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
+{
+ return ZSTD_sizeof_CCtx(zcs); /* same object */
+}
+
+/* private API call, for dictBuilder only */
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
+
+static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
+ ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params cctxParams;
+ memset(&cctxParams, 0, sizeof(cctxParams));
+ cctxParams.cParams = cParams;
+ cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ assert(!ZSTD_checkCParams(cParams));
+ cctxParams.fParams.contentSizeFlag = 1;
+ return cctxParams;
+}
+
+static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
+ ZSTD_customMem customMem)
+{
+ ZSTD_CCtx_params* params;
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+ params = (ZSTD_CCtx_params*)ZSTD_calloc(
+ sizeof(ZSTD_CCtx_params), customMem);
+ if (!params) { return NULL; }
+ params->customMem = customMem;
+ params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ params->fParams.contentSizeFlag = 1;
+ return params;
+}
+
+ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
+{
+ return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
+{
+ if (params == NULL) { return 0; }
+ ZSTD_free(params, params->customMem);
+ return 0;
+}
+
+size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
+{
+ return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
+}
+
+size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
+ if (!cctxParams) { return ERROR(GENERIC); }
+ memset(cctxParams, 0, sizeof(*cctxParams));
+ cctxParams->compressionLevel = compressionLevel;
+ cctxParams->fParams.contentSizeFlag = 1;
+ return 0;
+}
+
+size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
+{
+ if (!cctxParams) { return ERROR(GENERIC); }
+ CHECK_F( ZSTD_checkCParams(params.cParams) );
+ memset(cctxParams, 0, sizeof(*cctxParams));
+ cctxParams->cParams = params.cParams;
+ cctxParams->fParams = params.fParams;
+ cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ assert(!ZSTD_checkCParams(params.cParams));
+ return 0;
+}
+
+/* ZSTD_assignParamsToCCtxParams() :
+ * params is presumed valid at this stage */
+static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
+ ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
+{
+ ZSTD_CCtx_params ret = cctxParams;
+ ret.cParams = params.cParams;
+ ret.fParams = params.fParams;
+ ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ assert(!ZSTD_checkCParams(params.cParams));
+ return ret;
+}
+
+ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
+{
+ ZSTD_bounds bounds = { 0, 0, 0 };
+
+ switch(param)
+ {
+ case ZSTD_c_compressionLevel:
+ bounds.lowerBound = ZSTD_minCLevel();
+ bounds.upperBound = ZSTD_maxCLevel();
+ return bounds;
+
+ case ZSTD_c_windowLog:
+ bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
+ bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_hashLog:
+ bounds.lowerBound = ZSTD_HASHLOG_MIN;
+ bounds.upperBound = ZSTD_HASHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_chainLog:
+ bounds.lowerBound = ZSTD_CHAINLOG_MIN;
+ bounds.upperBound = ZSTD_CHAINLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_searchLog:
+ bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
+ bounds.upperBound = ZSTD_SEARCHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_minMatch:
+ bounds.lowerBound = ZSTD_MINMATCH_MIN;
+ bounds.upperBound = ZSTD_MINMATCH_MAX;
+ return bounds;
+
+ case ZSTD_c_targetLength:
+ bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
+ bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
+ return bounds;
+
+ case ZSTD_c_strategy:
+ bounds.lowerBound = ZSTD_STRATEGY_MIN;
+ bounds.upperBound = ZSTD_STRATEGY_MAX;
+ return bounds;
+
+ case ZSTD_c_contentSizeFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_checksumFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_dictIDFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_nbWorkers:
+ bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+ bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
+#else
+ bounds.upperBound = 0;
+#endif
+ return bounds;
+
+ case ZSTD_c_jobSize:
+ bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+ bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
+#else
+ bounds.upperBound = 0;
+#endif
+ return bounds;
+
+ case ZSTD_c_overlapLog:
+ bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
+ bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_enableLongDistanceMatching:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_ldmHashLog:
+ bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
+ bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmMinMatch:
+ bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
+ bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmBucketSizeLog:
+ bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
+ bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmHashRateLog:
+ bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
+ bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
+ return bounds;
+
+ /* experimental parameters */
+ case ZSTD_c_rsyncable:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_forceMaxWindow :
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_format:
+ ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+ bounds.lowerBound = ZSTD_f_zstd1;
+ bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */
+ return bounds;
+
+ case ZSTD_c_forceAttachDict:
+ ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
+ bounds.lowerBound = ZSTD_dictDefaultAttach;
+ bounds.upperBound = ZSTD_dictForceCopy; /* note : how to ensure at compile time that this is the highest value enum ? */
+ return bounds;
+
+ default:
+ { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 };
+ return boundError;
+ }
+ }
+}
+
+/* ZSTD_cParam_withinBounds:
+ * @return 1 if value is within cParam bounds,
+ * 0 otherwise */
+static int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
+{
+ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
+ if (ZSTD_isError(bounds.error)) return 0;
+ if (value < bounds.lowerBound) return 0;
+ if (value > bounds.upperBound) return 0;
+ return 1;
+}
+
+#define BOUNDCHECK(cParam, val) { \
+ if (!ZSTD_cParam_withinBounds(cParam,val)) { \
+ return ERROR(parameter_outOfBound); \
+} }
+
+
+static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
+{
+ switch(param)
+ {
+ case ZSTD_c_compressionLevel:
+ case ZSTD_c_hashLog:
+ case ZSTD_c_chainLog:
+ case ZSTD_c_searchLog:
+ case ZSTD_c_minMatch:
+ case ZSTD_c_targetLength:
+ case ZSTD_c_strategy:
+ return 1;
+
+ case ZSTD_c_format:
+ case ZSTD_c_windowLog:
+ case ZSTD_c_contentSizeFlag:
+ case ZSTD_c_checksumFlag:
+ case ZSTD_c_dictIDFlag:
+ case ZSTD_c_forceMaxWindow :
+ case ZSTD_c_nbWorkers:
+ case ZSTD_c_jobSize:
+ case ZSTD_c_overlapLog:
+ case ZSTD_c_rsyncable:
+ case ZSTD_c_enableLongDistanceMatching:
+ case ZSTD_c_ldmHashLog:
+ case ZSTD_c_ldmMinMatch:
+ case ZSTD_c_ldmBucketSizeLog:
+ case ZSTD_c_ldmHashRateLog:
+ case ZSTD_c_forceAttachDict:
+ default:
+ return 0;
+ }
+}
+
+size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
+ if (cctx->streamStage != zcss_init) {
+ if (ZSTD_isUpdateAuthorized(param)) {
+ cctx->cParamsChanged = 1;
+ } else {
+ return ERROR(stage_wrong);
+ } }
+
+ switch(param)
+ {
+ case ZSTD_c_format :
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_compressionLevel:
+ if (cctx->cdict) return ERROR(stage_wrong);
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_windowLog:
+ case ZSTD_c_hashLog:
+ case ZSTD_c_chainLog:
+ case ZSTD_c_searchLog:
+ case ZSTD_c_minMatch:
+ case ZSTD_c_targetLength:
+ case ZSTD_c_strategy:
+ if (cctx->cdict) return ERROR(stage_wrong);
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_contentSizeFlag:
+ case ZSTD_c_checksumFlag:
+ case ZSTD_c_dictIDFlag:
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_forceMaxWindow : /* Force back-references to remain < windowSize,
+ * even when referencing into Dictionary content.
+ * default : 0 when using a CDict, 1 when using a Prefix */
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_forceAttachDict:
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_nbWorkers:
+ if ((value!=0) && cctx->staticSize) {
+ return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
+ }
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_jobSize:
+ case ZSTD_c_overlapLog:
+ case ZSTD_c_rsyncable:
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ case ZSTD_c_enableLongDistanceMatching:
+ case ZSTD_c_ldmHashLog:
+ case ZSTD_c_ldmMinMatch:
+ case ZSTD_c_ldmBucketSizeLog:
+ case ZSTD_c_ldmHashRateLog:
+ if (cctx->cdict) return ERROR(stage_wrong);
+ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+ default: return ERROR(parameter_unsupported);
+ }
+}
+
+size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* CCtxParams,
+ ZSTD_cParameter param, int value)
+{
+ DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%i, %i)", (int)param, value);
+ switch(param)
+ {
+ case ZSTD_c_format :
+ BOUNDCHECK(ZSTD_c_format, value);
+ CCtxParams->format = (ZSTD_format_e)value;
+ return (size_t)CCtxParams->format;
+
+ case ZSTD_c_compressionLevel : {
+ int cLevel = value;
+ if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
+ if (cLevel < ZSTD_minCLevel()) cLevel = ZSTD_minCLevel();
+ if (cLevel) { /* 0 : does not change current level */
+ CCtxParams->compressionLevel = cLevel;
+ }
+ if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
+ return 0; /* return type (size_t) cannot represent negative values */
+ }
+
+ case ZSTD_c_windowLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_windowLog, value);
+ CCtxParams->cParams.windowLog = value;
+ return CCtxParams->cParams.windowLog;
+
+ case ZSTD_c_hashLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_hashLog, value);
+ CCtxParams->cParams.hashLog = value;
+ return CCtxParams->cParams.hashLog;
+
+ case ZSTD_c_chainLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_chainLog, value);
+ CCtxParams->cParams.chainLog = value;
+ return CCtxParams->cParams.chainLog;
+
+ case ZSTD_c_searchLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_searchLog, value);
+ CCtxParams->cParams.searchLog = value;
+ return value;
+
+ case ZSTD_c_minMatch :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_minMatch, value);
+ CCtxParams->cParams.minMatch = value;
+ return CCtxParams->cParams.minMatch;
+
+ case ZSTD_c_targetLength :
+ BOUNDCHECK(ZSTD_c_targetLength, value);
+ CCtxParams->cParams.targetLength = value;
+ return CCtxParams->cParams.targetLength;
+
+ case ZSTD_c_strategy :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_strategy, value);
+ CCtxParams->cParams.strategy = (ZSTD_strategy)value;
+ return (size_t)CCtxParams->cParams.strategy;
+
+ case ZSTD_c_contentSizeFlag :
+ /* Content size written in frame header _when known_ (default:1) */
+ DEBUGLOG(4, "set content size flag = %u", (value!=0));
+ CCtxParams->fParams.contentSizeFlag = value != 0;
+ return CCtxParams->fParams.contentSizeFlag;
+
+ case ZSTD_c_checksumFlag :
+ /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
+ CCtxParams->fParams.checksumFlag = value != 0;
+ return CCtxParams->fParams.checksumFlag;
+
+ case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
+ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
+ CCtxParams->fParams.noDictIDFlag = !value;
+ return !CCtxParams->fParams.noDictIDFlag;
+
+ case ZSTD_c_forceMaxWindow :
+ CCtxParams->forceWindow = (value != 0);
+ return CCtxParams->forceWindow;
+
+ case ZSTD_c_forceAttachDict : {
+ const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
+ BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
+ CCtxParams->attachDictPref = pref;
+ return CCtxParams->attachDictPref;
+ }
+
+ case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+ if (value!=0) return ERROR(parameter_unsupported);
+ return 0;
+#else
+ return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value);
+#endif
+
+ case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
+#endif
+
+ case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapLog, value);
+#endif
+
+ case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_rsyncable, value);
+#endif
+
+ case ZSTD_c_enableLongDistanceMatching :
+ CCtxParams->ldmParams.enableLdm = (value!=0);
+ return CCtxParams->ldmParams.enableLdm;
+
+ case ZSTD_c_ldmHashLog :
+ if (value!=0) /* 0 ==> auto */
+ BOUNDCHECK(ZSTD_c_ldmHashLog, value);
+ CCtxParams->ldmParams.hashLog = value;
+ return CCtxParams->ldmParams.hashLog;
+
+ case ZSTD_c_ldmMinMatch :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
+ CCtxParams->ldmParams.minMatchLength = value;
+ return CCtxParams->ldmParams.minMatchLength;
+
+ case ZSTD_c_ldmBucketSizeLog :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
+ CCtxParams->ldmParams.bucketSizeLog = value;
+ return CCtxParams->ldmParams.bucketSizeLog;
+
+ case ZSTD_c_ldmHashRateLog :
+ if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
+ return ERROR(parameter_outOfBound);
+ CCtxParams->ldmParams.hashRateLog = value;
+ return CCtxParams->ldmParams.hashRateLog;
+
+ default: return ERROR(parameter_unsupported);
+ }
+}
+
+size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
+{
+ return ZSTD_CCtxParam_getParameter(&cctx->requestedParams, param, value);
+}
+
+size_t ZSTD_CCtxParam_getParameter(
+ ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
+{
+ switch(param)
+ {
+ case ZSTD_c_format :
+ *value = CCtxParams->format;
+ break;
+ case ZSTD_c_compressionLevel :
+ *value = CCtxParams->compressionLevel;
+ break;
+ case ZSTD_c_windowLog :
+ *value = CCtxParams->cParams.windowLog;
+ break;
+ case ZSTD_c_hashLog :
+ *value = CCtxParams->cParams.hashLog;
+ break;
+ case ZSTD_c_chainLog :
+ *value = CCtxParams->cParams.chainLog;
+ break;
+ case ZSTD_c_searchLog :
+ *value = CCtxParams->cParams.searchLog;
+ break;
+ case ZSTD_c_minMatch :
+ *value = CCtxParams->cParams.minMatch;
+ break;
+ case ZSTD_c_targetLength :
+ *value = CCtxParams->cParams.targetLength;
+ break;
+ case ZSTD_c_strategy :
+ *value = (unsigned)CCtxParams->cParams.strategy;
+ break;
+ case ZSTD_c_contentSizeFlag :
+ *value = CCtxParams->fParams.contentSizeFlag;
+ break;
+ case ZSTD_c_checksumFlag :
+ *value = CCtxParams->fParams.checksumFlag;
+ break;
+ case ZSTD_c_dictIDFlag :
+ *value = !CCtxParams->fParams.noDictIDFlag;
+ break;
+ case ZSTD_c_forceMaxWindow :
+ *value = CCtxParams->forceWindow;
+ break;
+ case ZSTD_c_forceAttachDict :
+ *value = CCtxParams->attachDictPref;
+ break;
+ case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+ assert(CCtxParams->nbWorkers == 0);
+#endif
+ *value = CCtxParams->nbWorkers;
+ break;
+ case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ assert(CCtxParams->jobSize <= INT_MAX);
+ *value = (int)CCtxParams->jobSize;
+ break;
+#endif
+ case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ *value = CCtxParams->overlapLog;
+ break;
+#endif
+ case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ *value = CCtxParams->rsyncable;
+ break;
+#endif
+ case ZSTD_c_enableLongDistanceMatching :
+ *value = CCtxParams->ldmParams.enableLdm;
+ break;
+ case ZSTD_c_ldmHashLog :
+ *value = CCtxParams->ldmParams.hashLog;
+ break;
+ case ZSTD_c_ldmMinMatch :
+ *value = CCtxParams->ldmParams.minMatchLength;
+ break;
+ case ZSTD_c_ldmBucketSizeLog :
+ *value = CCtxParams->ldmParams.bucketSizeLog;
+ break;
+ case ZSTD_c_ldmHashRateLog :
+ *value = CCtxParams->ldmParams.hashRateLog;
+ break;
+ default: return ERROR(parameter_unsupported);
+ }
+ return 0;
+}
+
+/** ZSTD_CCtx_setParametersUsingCCtxParams() :
+ * just applies `params` into `cctx`
+ * no action is performed, parameters are merely stored.
+ * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
+ * This is possible even if a compression is ongoing.
+ * In which case, new parameters will be applied on the fly, starting with next compression job.
+ */
+size_t ZSTD_CCtx_setParametersUsingCCtxParams(
+ ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ if (cctx->cdict) return ERROR(stage_wrong);
+
+ cctx->requestedParams = *params;
+ return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+ return 0;
+}
+
+size_t ZSTD_CCtx_loadDictionary_advanced(
+ ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
+{
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
+ DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
+ ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
+ if (dict==NULL || dictSize==0) { /* no dictionary mode */
+ cctx->cdictLocal = NULL;
+ cctx->cdict = NULL;
+ } else {
+ ZSTD_compressionParameters const cParams =
+ ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize);
+ cctx->cdictLocal = ZSTD_createCDict_advanced(
+ dict, dictSize,
+ dictLoadMethod, dictContentType,
+ cParams, cctx->customMem);
+ cctx->cdict = cctx->cdictLocal;
+ if (cctx->cdictLocal == NULL)
+ return ERROR(memory_allocation);
+ }
+ return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
+ ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_CCtx_loadDictionary_advanced(
+ cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_CCtx_loadDictionary_advanced(
+ cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+
+size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ cctx->cdict = cdict;
+ memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */
+ return 0;
+}
+
+size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
+{
+ return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+size_t ZSTD_CCtx_refPrefix_advanced(
+ ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ cctx->cdict = NULL; /* prefix discards any prior cdict */
+ cctx->prefixDict.dict = prefix;
+ cctx->prefixDict.dictSize = prefixSize;
+ cctx->prefixDict.dictContentType = dictContentType;
+ return 0;
+}
+
+/*! ZSTD_CCtx_reset() :
+ * Also dumps dictionary */
+size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
+{
+ if ( (reset == ZSTD_reset_session_only)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ cctx->streamStage = zcss_init;
+ cctx->pledgedSrcSizePlusOne = 0;
+ }
+ if ( (reset == ZSTD_reset_parameters)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+ cctx->cdict = NULL;
+ return ZSTD_CCtxParams_reset(&cctx->requestedParams);
+ }
+ return 0;
+}
+
+
+/** ZSTD_checkCParams() :
+ control CParam values remain within authorized range.
+ @return : 0, or an error code if one value is beyond authorized range */
+size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
+{
+ BOUNDCHECK(ZSTD_c_windowLog, cParams.windowLog);
+ BOUNDCHECK(ZSTD_c_chainLog, cParams.chainLog);
+ BOUNDCHECK(ZSTD_c_hashLog, cParams.hashLog);
+ BOUNDCHECK(ZSTD_c_searchLog, cParams.searchLog);
+ BOUNDCHECK(ZSTD_c_minMatch, cParams.minMatch);
+ BOUNDCHECK(ZSTD_c_targetLength,cParams.targetLength);
+ BOUNDCHECK(ZSTD_c_strategy, cParams.strategy);
+ return 0;
+}
+
+/** ZSTD_clampCParams() :
+ * make CParam values within valid range.
+ * @return : valid CParams */
+static ZSTD_compressionParameters
+ZSTD_clampCParams(ZSTD_compressionParameters cParams)
+{
+# define CLAMP_TYPE(cParam, val, type) { \
+ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
+ if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
+ else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
+ }
+# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, int)
+ CLAMP(ZSTD_c_windowLog, cParams.windowLog);
+ CLAMP(ZSTD_c_chainLog, cParams.chainLog);
+ CLAMP(ZSTD_c_hashLog, cParams.hashLog);
+ CLAMP(ZSTD_c_searchLog, cParams.searchLog);
+ CLAMP(ZSTD_c_minMatch, cParams.minMatch);
+ CLAMP(ZSTD_c_targetLength,cParams.targetLength);
+ CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
+ return cParams;
+}
+
+/** ZSTD_cycleLog() :
+ * condition for correct operation : hashLog > 1 */
+static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
+{
+ U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
+ return hashLog - btScale;
+}
+
+/** ZSTD_adjustCParams_internal() :
+ optimize `cPar` for a given input (`srcSize` and `dictSize`).
+ mostly downsizing to reduce memory consumption and initialization latency.
+ Both `srcSize` and `dictSize` are optional (use 0 if unknown).
+ Note : cPar is assumed validated. Use ZSTD_checkCParams() to ensure this condition. */
+static ZSTD_compressionParameters
+ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
+ unsigned long long srcSize,
+ size_t dictSize)
+{
+ static const U64 minSrcSize = 513; /* (1<<9) + 1 */
+ static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
+ assert(ZSTD_checkCParams(cPar)==0);
+
+ if (dictSize && (srcSize+1<2) /* srcSize unknown */ )
+ srcSize = minSrcSize; /* presumed small when there is a dictionary */
+ else if (srcSize == 0)
+ srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */
+
+ /* resize windowLog if input is small enough, to use less memory */
+ if ( (srcSize < maxWindowResize)
+ && (dictSize < maxWindowResize) ) {
+ U32 const tSize = (U32)(srcSize + dictSize);
+ static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
+ U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
+ ZSTD_highbit32(tSize-1) + 1;
+ if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
+ }
+ if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
+ { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
+ if (cycleLog > cPar.windowLog)
+ cPar.chainLog -= (cycleLog - cPar.windowLog);
+ }
+
+ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
+ cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
+
+ return cPar;
+}
+
+ZSTD_compressionParameters
+ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
+ unsigned long long srcSize,
+ size_t dictSize)
+{
+ cPar = ZSTD_clampCParams(cPar);
+ return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
+}
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
+{
+ ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
+ if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
+ if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
+ if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
+ if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
+ if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
+ if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
+ if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
+ if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
+ assert(!ZSTD_checkCParams(cParams));
+ return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
+}
+
+static size_t
+ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+ const U32 forCCtx)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+ size_t const h3Size = ((size_t)1) << hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+ size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
+ + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
+ size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
+ ? optPotentialSpace
+ : 0;
+ DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
+ (U32)chainSize, (U32)hSize, (U32)h3Size);
+ return tableSpace + optSpace;
+}
+
+size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+ /* Estimate CCtx size is supported for single-threaded compression only. */
+ if (params->nbWorkers > 0) { return ERROR(GENERIC); }
+ { ZSTD_compressionParameters const cParams =
+ ZSTD_getCParamsFromCCtxParams(params, 0, 0);
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
+ U32 const divider = (cParams.minMatch==3) ? 3 : 4;
+ size_t const maxNbSeq = blockSize / divider;
+ size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
+ size_t const entropySpace = HUF_WORKSPACE_SIZE;
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
+
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
+ size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
+
+ size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
+ matchStateSize + ldmSpace + ldmSeqSpace;
+
+ DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
+ DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
+ return sizeof(ZSTD_CCtx) + neededSpace;
+ }
+}
+
+size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+ return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
+ return ZSTD_estimateCCtxSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCCtxSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
+size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+ if (params->nbWorkers > 0) { return ERROR(GENERIC); }
+ { size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
+ size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
+ size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
+ size_t const streamingSize = inBuffSize + outBuffSize;
+
+ return CCtxSize + streamingSize;
+ }
+}
+
+size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+ return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
+ return ZSTD_estimateCStreamSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCStreamSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
+/* ZSTD_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads (non-blocking mode).
+ */
+ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ return ZSTDMT_getFrameProgression(cctx->mtctx);
+ }
+#endif
+ { ZSTD_frameProgression fp;
+ size_t const buffered = (cctx->inBuff == NULL) ? 0 :
+ cctx->inBuffPos - cctx->inToCompress;
+ if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
+ assert(buffered <= ZSTD_BLOCKSIZE_MAX);
+ fp.ingested = cctx->consumedSrcSize + buffered;
+ fp.consumed = cctx->consumedSrcSize;
+ fp.produced = cctx->producedCSize;
+ fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
+ fp.currentJobID = 0;
+ fp.nbActiveWorkers = 0;
+ return fp;
+} }
+
+/*! ZSTD_toFlushNow()
+ * Only useful for multithreading scenarios currently (nbWorkers >= 1).
+ */
+size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ return ZSTDMT_toFlushNow(cctx->mtctx);
+ }
+#endif
+ (void)cctx;
+ return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */
+}
+
+
+
+static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
+ ZSTD_compressionParameters cParams2)
+{
+ return (cParams1.hashLog == cParams2.hashLog)
+ & (cParams1.chainLog == cParams2.chainLog)
+ & (cParams1.strategy == cParams2.strategy) /* opt parser space */
+ & ((cParams1.minMatch==3) == (cParams2.minMatch==3)); /* hashlog3 space */
+}
+
+static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
+ ZSTD_compressionParameters cParams2)
+{
+ (void)cParams1;
+ (void)cParams2;
+ assert(cParams1.windowLog == cParams2.windowLog);
+ assert(cParams1.chainLog == cParams2.chainLog);
+ assert(cParams1.hashLog == cParams2.hashLog);
+ assert(cParams1.searchLog == cParams2.searchLog);
+ assert(cParams1.minMatch == cParams2.minMatch);
+ assert(cParams1.targetLength == cParams2.targetLength);
+ assert(cParams1.strategy == cParams2.strategy);
+}
+
+/** The parameters are equivalent if ldm is not enabled in both sets or
+ * all the parameters are equivalent. */
+static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
+ ldmParams_t ldmParams2)
+{
+ return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
+ (ldmParams1.enableLdm == ldmParams2.enableLdm &&
+ ldmParams1.hashLog == ldmParams2.hashLog &&
+ ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
+ ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
+ ldmParams1.hashRateLog == ldmParams2.hashRateLog);
+}
+
+typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
+
+/* ZSTD_sufficientBuff() :
+ * check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
+ * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
+static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1,
+ size_t maxNbLit1,
+ ZSTD_buffered_policy_e buffPol2,
+ ZSTD_compressionParameters cParams2,
+ U64 pledgedSrcSize)
+{
+ size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
+ size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
+ size_t const maxNbSeq2 = blockSize2 / ((cParams2.minMatch == 3) ? 3 : 4);
+ size_t const maxNbLit2 = blockSize2;
+ size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
+ DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u",
+ (U32)neededBufferSize2, (U32)bufferSize1);
+ DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u",
+ (U32)maxNbSeq2, (U32)maxNbSeq1);
+ DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u",
+ (U32)maxNbLit2, (U32)maxNbLit1);
+ return (maxNbLit2 <= maxNbLit1)
+ & (maxNbSeq2 <= maxNbSeq1)
+ & (neededBufferSize2 <= bufferSize1);
+}
+
+/** Equivalence for resetCCtx purposes */
+static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
+ ZSTD_CCtx_params params2,
+ size_t buffSize1,
+ size_t maxNbSeq1, size_t maxNbLit1,
+ ZSTD_buffered_policy_e buffPol2,
+ U64 pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize);
+ if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) {
+ DEBUGLOG(4, "ZSTD_equivalentCParams() == 0");
+ return 0;
+ }
+ if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) {
+ DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0");
+ return 0;
+ }
+ if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2,
+ params2.cParams, pledgedSrcSize)) {
+ DEBUGLOG(4, "ZSTD_sufficientBuff() == 0");
+ return 0;
+ }
+ return 1;
+}
+
+static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
+{
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; ++i)
+ bs->rep[i] = repStartValue[i];
+ bs->entropy.huf.repeatMode = HUF_repeat_none;
+ bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
+ bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
+ bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
+}
+
+/*! ZSTD_invalidateMatchState()
+ * Invalidate all the matches in the match finder tables.
+ * Requires nextSrc and base to be set (can be NULL).
+ */
+static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
+{
+ ZSTD_window_clear(&ms->window);
+
+ ms->nextToUpdate = ms->window.dictLimit;
+ ms->nextToUpdate3 = ms->window.dictLimit;
+ ms->loadedDictEnd = 0;
+ ms->opt.litLengthSum = 0; /* force reset of btopt stats */
+ ms->dictMatchState = NULL;
+}
+
+/*! ZSTD_continueCCtx() :
+ * reuse CCtx without reset (note : requires no dictionary) */
+static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
+{
+ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+ DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
+
+ cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
+ cctx->appliedParams = params;
+ cctx->blockState.matchState.cParams = params.cParams;
+ cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+ cctx->consumedSrcSize = 0;
+ cctx->producedCSize = 0;
+ if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+ cctx->appliedParams.fParams.contentSizeFlag = 0;
+ DEBUGLOG(4, "pledged content size : %u ; flag : %u",
+ (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
+ cctx->stage = ZSTDcs_init;
+ cctx->dictID = 0;
+ if (params.ldmParams.enableLdm)
+ ZSTD_window_clear(&cctx->ldmState.window);
+ ZSTD_referenceExternalSequences(cctx, NULL, 0);
+ ZSTD_invalidateMatchState(&cctx->blockState.matchState);
+ ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
+ XXH64_reset(&cctx->xxhState, 0);
+ return 0;
+}
+
+typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
+
+static void*
+ZSTD_reset_matchState(ZSTD_matchState_t* ms,
+ void* ptr,
+ const ZSTD_compressionParameters* cParams,
+ ZSTD_compResetPolicy_e const crp, U32 const forCCtx)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+ size_t const h3Size = ((size_t)1) << hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+
+ assert(((size_t)ptr & 3) == 0);
+
+ ms->hashLog3 = hashLog3;
+ memset(&ms->window, 0, sizeof(ms->window));
+ ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */
+ ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
+ ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */
+ ZSTD_invalidateMatchState(ms);
+
+ /* opt parser space */
+ if (forCCtx && (cParams->strategy >= ZSTD_btopt)) {
+ DEBUGLOG(4, "reserving optimal parser space");
+ ms->opt.litFreq = (unsigned*)ptr;
+ ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits);
+ ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1);
+ ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1);
+ ptr = ms->opt.offCodeFreq + (MaxOff+1);
+ ms->opt.matchTable = (ZSTD_match_t*)ptr;
+ ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1;
+ ms->opt.priceTable = (ZSTD_optimal_t*)ptr;
+ ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1;
+ }
+
+ /* table Space */
+ DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
+ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+ if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
+ ms->hashTable = (U32*)(ptr);
+ ms->chainTable = ms->hashTable + hSize;
+ ms->hashTable3 = ms->chainTable + chainSize;
+ ptr = ms->hashTable3 + h3Size;
+
+ ms->cParams = *cParams;
+
+ assert(((size_t)ptr & 3) == 0);
+ return ptr;
+}
+
+#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */
+#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large
+ * during at least this number of times,
+ * context's memory usage is considered wasteful,
+ * because it's sized to handle a worst case scenario which rarely happens.
+ * In which case, resize it down to free some memory */
+
+/*! ZSTD_resetCCtx_internal() :
+ note : `params` are assumed fully validated at this stage */
+static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_compResetPolicy_e const crp,
+ ZSTD_buffered_policy_e const zbuff)
+{
+ DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
+ (U32)pledgedSrcSize, params.cParams.windowLog);
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+
+ if (crp == ZSTDcrp_continue) {
+ if (ZSTD_equivalentParams(zc->appliedParams, params,
+ zc->inBuffSize,
+ zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit,
+ zbuff, pledgedSrcSize)) {
+ DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)",
+ zc->appliedParams.cParams.windowLog, zc->blockSize);
+ zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */
+ if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION)
+ return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
+ } }
+ DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
+
+ if (params.ldmParams.enableLdm) {
+ /* Adjust long distance matching parameters */
+ ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
+ assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
+ assert(params.ldmParams.hashRateLog < 32);
+ zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+ }
+
+ { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+ U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
+ size_t const maxNbSeq = blockSize / divider;
+ size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
+ size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
+ size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
+ size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
+ void* ptr; /* used to partition workSpace */
+
+ /* Check if workSpace is large enough, alloc a new one if needed */
+ { size_t const entropySpace = HUF_WORKSPACE_SIZE;
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
+ size_t const bufferSpace = buffInSize + buffOutSize;
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
+ size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
+
+ size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
+ ldmSeqSpace + matchStateSize + tokenSpace +
+ bufferSpace;
+
+ int const workSpaceTooSmall = zc->workSpaceSize < neededSpace;
+ int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace;
+ int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION);
+ zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0;
+
+ DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
+ neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
+ DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
+
+ if (workSpaceTooSmall || workSpaceWasteful) {
+ DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB",
+ zc->workSpaceSize >> 10,
+ neededSpace >> 10);
+ /* static cctx : no resize, error out */
+ if (zc->staticSize) return ERROR(memory_allocation);
+
+ zc->workSpaceSize = 0;
+ ZSTD_free(zc->workSpace, zc->customMem);
+ zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
+ if (zc->workSpace == NULL) return ERROR(memory_allocation);
+ zc->workSpaceSize = neededSpace;
+ zc->workSpaceOversizedDuration = 0;
+
+ /* Statically sized space.
+ * entropyWorkspace never moves,
+ * though prev/next block swap places */
+ assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
+ assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
+ zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
+ zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
+ ptr = zc->blockState.nextCBlock + 1;
+ zc->entropyWorkspace = (U32*)ptr;
+ } }
+
+ /* init params */
+ zc->appliedParams = params;
+ zc->blockState.matchState.cParams = params.cParams;
+ zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+ zc->consumedSrcSize = 0;
+ zc->producedCSize = 0;
+ if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+ zc->appliedParams.fParams.contentSizeFlag = 0;
+ DEBUGLOG(4, "pledged content size : %u ; flag : %u",
+ (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
+ zc->blockSize = blockSize;
+
+ XXH64_reset(&zc->xxhState, 0);
+ zc->stage = ZSTDcs_init;
+ zc->dictID = 0;
+
+ ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
+
+ ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
+
+ /* ldm hash table */
+ /* initialize bucketOffsets table later for pointer alignment */
+ if (params.ldmParams.enableLdm) {
+ size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
+ memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
+ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+ zc->ldmState.hashTable = (ldmEntry_t*)ptr;
+ ptr = zc->ldmState.hashTable + ldmHSize;
+ zc->ldmSequences = (rawSeq*)ptr;
+ ptr = zc->ldmSequences + maxNbLdmSeq;
+ zc->maxNbLdmSequences = maxNbLdmSeq;
+
+ memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window));
+ }
+ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+
+ ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, &params.cParams, crp, /* forCCtx */ 1);
+
+ /* sequences storage */
+ zc->seqStore.maxNbSeq = maxNbSeq;
+ zc->seqStore.sequencesStart = (seqDef*)ptr;
+ ptr = zc->seqStore.sequencesStart + maxNbSeq;
+ zc->seqStore.llCode = (BYTE*) ptr;
+ zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
+ zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
+ zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
+ /* ZSTD_wildcopy() is used to copy into the literals buffer,
+ * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
+ */
+ zc->seqStore.maxNbLit = blockSize;
+ ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH;
+
+ /* ldm bucketOffsets table */
+ if (params.ldmParams.enableLdm) {
+ size_t const ldmBucketSize =
+ ((size_t)1) << (params.ldmParams.hashLog -
+ params.ldmParams.bucketSizeLog);
+ memset(ptr, 0, ldmBucketSize);
+ zc->ldmState.bucketOffsets = (BYTE*)ptr;
+ ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
+ ZSTD_window_clear(&zc->ldmState.window);
+ }
+ ZSTD_referenceExternalSequences(zc, NULL, 0);
+
+ /* buffers */
+ zc->inBuffSize = buffInSize;
+ zc->inBuff = (char*)ptr;
+ zc->outBuffSize = buffOutSize;
+ zc->outBuff = zc->inBuff + buffInSize;
+
+ return 0;
+ }
+}
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ * do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
+ int i;
+ for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
+ assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
+}
+
+/* These are the approximate sizes for each strategy past which copying the
+ * dictionary tables into the working context is faster than using them
+ * in-place.
+ */
+static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
+ 8 KB, /* unused */
+ 8 KB, /* ZSTD_fast */
+ 16 KB, /* ZSTD_dfast */
+ 32 KB, /* ZSTD_greedy */
+ 32 KB, /* ZSTD_lazy */
+ 32 KB, /* ZSTD_lazy2 */
+ 32 KB, /* ZSTD_btlazy2 */
+ 32 KB, /* ZSTD_btopt */
+ 8 KB, /* ZSTD_btultra */
+ 8 KB /* ZSTD_btultra2 */
+};
+
+static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize)
+{
+ size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
+ return ( pledgedSrcSize <= cutoff
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+ || params.attachDictPref == ZSTD_dictForceAttach )
+ && params.attachDictPref != ZSTD_dictForceCopy
+ && !params.forceWindow; /* dictMatchState isn't correctly
+ * handled in _enforceMaxDist */
+}
+
+static size_t ZSTD_resetCCtx_byAttachingCDict(
+ ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ {
+ const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
+ unsigned const windowLog = params.cParams.windowLog;
+ assert(windowLog != 0);
+ /* Resize working context table params for input only, since the dict
+ * has its own tables. */
+ params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
+ params.cParams.windowLog = windowLog;
+ ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_continue, zbuff);
+ assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+ }
+
+ {
+ const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
+ - cdict->matchState.window.base);
+ const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
+ if (cdictLen == 0) {
+ /* don't even attach dictionaries with no contents */
+ DEBUGLOG(4, "skipping attaching empty dictionary");
+ } else {
+ DEBUGLOG(4, "attaching dictionary into context");
+ cctx->blockState.matchState.dictMatchState = &cdict->matchState;
+
+ /* prep working match state so dict matches never have negative indices
+ * when they are translated to the working context's index space. */
+ if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
+ cctx->blockState.matchState.window.nextSrc =
+ cctx->blockState.matchState.window.base + cdictEnd;
+ ZSTD_window_clear(&cctx->blockState.matchState.window);
+ }
+ cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
+ }
+ }
+
+ cctx->dictID = cdict->dictID;
+
+ /* copy block state */
+ memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+ return 0;
+}
+
+static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
+
+ DEBUGLOG(4, "copying dictionary into context");
+
+ { unsigned const windowLog = params.cParams.windowLog;
+ assert(windowLog != 0);
+ /* Copy only compression parameters related to tables. */
+ params.cParams = *cdict_cParams;
+ params.cParams.windowLog = windowLog;
+ ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_noMemset, zbuff);
+ assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+ assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
+ assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
+ }
+
+ /* copy tables */
+ { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
+ size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
+ size_t const tableSpace = (chainSize + hSize) * sizeof(U32);
+ assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
+ assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
+ memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
+ }
+
+ /* Zero the hashTable3, since the cdict never fills it */
+ { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
+ assert(cdict->matchState.hashLog3 == 0);
+ memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
+ }
+
+ /* copy dictionary offsets */
+ { ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
+ ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
+ dstMatchState->window = srcMatchState->window;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+ }
+
+ cctx->dictID = cdict->dictID;
+
+ /* copy block state */
+ memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+ return 0;
+}
+
+/* We have a choice between copying the dictionary context into the working
+ * context, or referencing the dictionary context from the working context
+ * in-place. We decide here which strategy to use. */
+static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+
+ DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
+ (unsigned)pledgedSrcSize);
+
+ if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
+ return ZSTD_resetCCtx_byAttachingCDict(
+ cctx, cdict, params, pledgedSrcSize, zbuff);
+ } else {
+ return ZSTD_resetCCtx_byCopyingCDict(
+ cctx, cdict, params, pledgedSrcSize, zbuff);
+ }
+}
+
+/*! ZSTD_copyCCtx_internal() :
+ * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ * The "context", in this case, refers to the hash and chain tables,
+ * entropy tables, and dictionary references.
+ * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
+ * @return : 0, or an error code */
+static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
+ const ZSTD_CCtx* srcCCtx,
+ ZSTD_frameParameters fParams,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ DEBUGLOG(5, "ZSTD_copyCCtx_internal");
+ if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
+
+ memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
+ { ZSTD_CCtx_params params = dstCCtx->requestedParams;
+ /* Copy only compression parameters related to tables. */
+ params.cParams = srcCCtx->appliedParams.cParams;
+ params.fParams = fParams;
+ ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
+ ZSTDcrp_noMemset, zbuff);
+ assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
+ assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
+ assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
+ assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
+ assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
+ }
+
+ /* copy tables */
+ { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
+ size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
+ size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+ assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
+ memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
+ }
+
+ /* copy dictionary offsets */
+ {
+ const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
+ ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
+ dstMatchState->window = srcMatchState->window;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+ }
+ dstCCtx->dictID = srcCCtx->dictID;
+
+ /* copy block state */
+ memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
+
+ return 0;
+}
+
+/*! ZSTD_copyCCtx() :
+ * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ * pledgedSrcSize==0 means "unknown".
+* @return : 0, or an error code */
+size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
+{
+ ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
+ ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
+ if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
+
+ return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
+ fParams, pledgedSrcSize,
+ zbuff);
+}
+
+
+#define ZSTD_ROWSIZE 16
+/*! ZSTD_reduceTable() :
+ * reduce table indexes by `reducerValue`, or squash to zero.
+ * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
+ * It must be set to a clear 0/1 value, to remove branch during inlining.
+ * Presume table size is a multiple of ZSTD_ROWSIZE
+ * to help auto-vectorization */
+FORCE_INLINE_TEMPLATE void
+ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
+{
+ int const nbRows = (int)size / ZSTD_ROWSIZE;
+ int cellNb = 0;
+ int rowNb;
+ assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
+ assert(size < (1U<<31)); /* can be casted to int */
+ for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
+ int column;
+ for (column=0; column<ZSTD_ROWSIZE; column++) {
+ if (preserveMark) {
+ U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
+ table[cellNb] += adder;
+ }
+ if (table[cellNb] < reducerValue) table[cellNb] = 0;
+ else table[cellNb] -= reducerValue;
+ cellNb++;
+ } }
+}
+
+static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
+{
+ ZSTD_reduceTable_internal(table, size, reducerValue, 0);
+}
+
+static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
+{
+ ZSTD_reduceTable_internal(table, size, reducerValue, 1);
+}
+
+/*! ZSTD_reduceIndex() :
+* rescale all indexes to avoid future overflow (indexes are U32) */
+static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
+{
+ ZSTD_matchState_t* const ms = &zc->blockState.matchState;
+ { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
+ ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
+ }
+
+ if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
+ U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
+ if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
+ ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
+ else
+ ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
+ }
+
+ if (ms->hashLog3) {
+ U32 const h3Size = (U32)1 << ms->hashLog3;
+ ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
+ }
+}
+
+
+/*-*******************************************************
+* Block entropic compression
+*********************************************************/
+
+/* See doc/zstd_compression_format.md for detailed format description */
+
+static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock)
+{
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3);
+ if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
+ MEM_writeLE24(dst, cBlockHeader24);
+ memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
+ return ZSTD_blockHeaderSize + srcSize;
+}
+
+static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ BYTE* const ostart = (BYTE* const)dst;
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+ if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
+
+ switch(flSize)
+ {
+ case 1: /* 2 - 1 - 5 */
+ ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
+ break;
+ case 2: /* 2 - 2 - 12 */
+ MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
+ break;
+ case 3: /* 2 - 2 - 20 */
+ MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
+ break;
+ default: /* not necessary : flSize is {1,2,3} */
+ assert(0);
+ }
+
+ memcpy(ostart + flSize, src, srcSize);
+ return srcSize + flSize;
+}
+
+static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ BYTE* const ostart = (BYTE* const)dst;
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+ (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
+
+ switch(flSize)
+ {
+ case 1: /* 2 - 1 - 5 */
+ ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
+ break;
+ case 2: /* 2 - 2 - 12 */
+ MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
+ break;
+ case 3: /* 2 - 2 - 20 */
+ MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
+ break;
+ default: /* not necessary : flSize is {1,2,3} */
+ assert(0);
+ }
+
+ ostart[flSize] = *(const BYTE*)src;
+ return flSize+1;
+}
+
+
+/* ZSTD_minGain() :
+ * minimum compression required
+ * to generate a compress block or a compressed literals section.
+ * note : use same formula for both situations */
+static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
+{
+ U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
+ ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+ return (srcSize >> minlog) + 2;
+}
+
+static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
+ ZSTD_hufCTables_t* nextHuf,
+ ZSTD_strategy strategy, int disableLiteralCompression,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ void* workspace, size_t wkspSize,
+ const int bmi2)
+{
+ size_t const minGain = ZSTD_minGain(srcSize, strategy);
+ size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
+ BYTE* const ostart = (BYTE*)dst;
+ U32 singleStream = srcSize < 256;
+ symbolEncodingType_e hType = set_compressed;
+ size_t cLitSize;
+
+ DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
+ disableLiteralCompression);
+
+ /* Prepare nextEntropy assuming reusing the existing table */
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+ if (disableLiteralCompression)
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+
+ /* small ? don't even attempt compression (speed opt) */
+# define COMPRESS_LITERALS_SIZE_MIN 63
+ { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+ if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+ }
+
+ if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
+ { HUF_repeat repeat = prevHuf->repeatMode;
+ int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
+ if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
+ cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
+ workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
+ : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
+ workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
+ if (repeat != HUF_repeat_none) {
+ /* reused the existing table */
+ hType = set_repeat;
+ }
+ }
+
+ if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+ }
+ if (cLitSize==1) {
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
+ }
+
+ if (hType == set_compressed) {
+ /* using a newly constructed table */
+ nextHuf->repeatMode = HUF_repeat_check;
+ }
+
+ /* Build header */
+ switch(lhSize)
+ {
+ case 3: /* 2 - 2 - 10 - 10 */
+ { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
+ MEM_writeLE24(ostart, lhc);
+ break;
+ }
+ case 4: /* 2 - 2 - 14 - 14 */
+ { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
+ MEM_writeLE32(ostart, lhc);
+ break;
+ }
+ case 5: /* 2 - 2 - 18 - 18 */
+ { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
+ MEM_writeLE32(ostart, lhc);
+ ostart[4] = (BYTE)(cLitSize >> 10);
+ break;
+ }
+ default: /* not possible : lhSize is {3,4,5} */
+ assert(0);
+ }
+ return lhSize+cLitSize;
+}
+
+
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
+{
+ const seqDef* const sequences = seqStorePtr->sequencesStart;
+ BYTE* const llCodeTable = seqStorePtr->llCode;
+ BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ U32 u;
+ assert(nbSeq <= seqStorePtr->maxNbSeq);
+ for (u=0; u<nbSeq; u++) {
+ U32 const llv = sequences[u].litLength;
+ U32 const mlv = sequences[u].matchLength;
+ llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
+ ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
+ mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
+ }
+ if (seqStorePtr->longLengthID==1)
+ llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
+ if (seqStorePtr->longLengthID==2)
+ mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
+}
+
+
+/**
+ * -log2(x / 256) lookup table for x in [0, 256).
+ * If x == 0: Return 0
+ * Else: Return floor(-log2(x / 256) * 256)
+ */
+static unsigned const kInverseProbabiltyLog256[256] = {
+ 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
+ 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
+ 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
+ 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
+ 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
+ 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
+ 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
+ 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
+ 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
+ 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
+ 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
+ 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
+ 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
+ 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
+ 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
+ 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
+ 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
+ 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
+ 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
+ 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
+ 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
+ 5, 4, 2, 1,
+};
+
+
+/**
+ * Returns the cost in bits of encoding the distribution described by count
+ * using the entropy bound.
+ */
+static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
+{
+ unsigned cost = 0;
+ unsigned s;
+ for (s = 0; s <= max; ++s) {
+ unsigned norm = (unsigned)((256 * count[s]) / total);
+ if (count[s] != 0 && norm == 0)
+ norm = 1;
+ assert(count[s] < total);
+ cost += count[s] * kInverseProbabiltyLog256[norm];
+ }
+ return cost >> 8;
+}
+
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using the
+ * table described by norm. The max symbol support by norm is assumed >= max.
+ * norm must be valid for every symbol with non-zero probability in count.
+ */
+static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
+ unsigned const* count, unsigned const max)
+{
+ unsigned const shift = 8 - accuracyLog;
+ size_t cost = 0;
+ unsigned s;
+ assert(accuracyLog <= 8);
+ for (s = 0; s <= max; ++s) {
+ unsigned const normAcc = norm[s] != -1 ? norm[s] : 1;
+ unsigned const norm256 = normAcc << shift;
+ assert(norm256 > 0);
+ assert(norm256 < 256);
+ cost += count[s] * kInverseProbabiltyLog256[norm256];
+ }
+ return cost >> 8;
+}
+
+
+static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
+ void const* ptr = ctable;
+ U16 const* u16ptr = (U16 const*)ptr;
+ U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
+ return maxSymbolValue;
+}
+
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using ctable.
+ * Returns an error if ctable cannot represent all the symbols in count.
+ */
+static size_t ZSTD_fseBitCost(
+ FSE_CTable const* ctable,
+ unsigned const* count,
+ unsigned const max)
+{
+ unsigned const kAccuracyLog = 8;
+ size_t cost = 0;
+ unsigned s;
+ FSE_CState_t cstate;
+ FSE_initCState(&cstate, ctable);
+ if (ZSTD_getFSEMaxSymbolValue(ctable) < max) {
+ DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u",
+ ZSTD_getFSEMaxSymbolValue(ctable), max);
+ return ERROR(GENERIC);
+ }
+ for (s = 0; s <= max; ++s) {
+ unsigned const tableLog = cstate.stateLog;
+ unsigned const badCost = (tableLog + 1) << kAccuracyLog;
+ unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
+ if (count[s] == 0)
+ continue;
+ if (bitCost >= badCost) {
+ DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s);
+ return ERROR(GENERIC);
+ }
+ cost += count[s] * bitCost;
+ }
+ return cost >> kAccuracyLog;
+}
+
+/**
+ * Returns the cost in bytes of encoding the normalized count header.
+ * Returns an error if any of the helper functions return an error.
+ */
+static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
+ size_t const nbSeq, unsigned const FSELog)
+{
+ BYTE wksp[FSE_NCOUNTBOUND];
+ S16 norm[MaxSeq + 1];
+ const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+ CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq, max));
+ return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
+}
+
+
+typedef enum {
+ ZSTD_defaultDisallowed = 0,
+ ZSTD_defaultAllowed = 1
+} ZSTD_defaultPolicy_e;
+
+MEM_STATIC symbolEncodingType_e
+ZSTD_selectEncodingType(
+ FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
+ size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
+ FSE_CTable const* prevCTable,
+ short const* defaultNorm, U32 defaultNormLog,
+ ZSTD_defaultPolicy_e const isDefaultAllowed,
+ ZSTD_strategy const strategy)
+{
+ ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
+ if (mostFrequent == nbSeq) {
+ *repeatMode = FSE_repeat_none;
+ if (isDefaultAllowed && nbSeq <= 2) {
+ /* Prefer set_basic over set_rle when there are 2 or less symbols,
+ * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
+ * If basic encoding isn't possible, always choose RLE.
+ */
+ DEBUGLOG(5, "Selected set_basic");
+ return set_basic;
+ }
+ DEBUGLOG(5, "Selected set_rle");
+ return set_rle;
+ }
+ if (strategy < ZSTD_lazy) {
+ if (isDefaultAllowed) {
+ size_t const staticFse_nbSeq_max = 1000;
+ size_t const mult = 10 - strategy;
+ size_t const baseLog = 3;
+ size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
+ assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
+ assert(mult <= 9 && mult >= 7);
+ if ( (*repeatMode == FSE_repeat_valid)
+ && (nbSeq < staticFse_nbSeq_max) ) {
+ DEBUGLOG(5, "Selected set_repeat");
+ return set_repeat;
+ }
+ if ( (nbSeq < dynamicFse_nbSeq_min)
+ || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
+ DEBUGLOG(5, "Selected set_basic");
+ /* The format allows default tables to be repeated, but it isn't useful.
+ * When using simple heuristics to select encoding type, we don't want
+ * to confuse these tables with dictionaries. When running more careful
+ * analysis, we don't need to waste time checking both repeating tables
+ * and default tables.
+ */
+ *repeatMode = FSE_repeat_none;
+ return set_basic;
+ }
+ }
+ } else {
+ size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
+ size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
+ size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
+ size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
+
+ if (isDefaultAllowed) {
+ assert(!ZSTD_isError(basicCost));
+ assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
+ }
+ assert(!ZSTD_isError(NCountCost));
+ assert(compressedCost < ERROR(maxCode));
+ DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
+ (unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
+ if (basicCost <= repeatCost && basicCost <= compressedCost) {
+ DEBUGLOG(5, "Selected set_basic");
+ assert(isDefaultAllowed);
+ *repeatMode = FSE_repeat_none;
+ return set_basic;
+ }
+ if (repeatCost <= compressedCost) {
+ DEBUGLOG(5, "Selected set_repeat");
+ assert(!ZSTD_isError(repeatCost));
+ return set_repeat;
+ }
+ assert(compressedCost < basicCost && compressedCost < repeatCost);
+ }
+ DEBUGLOG(5, "Selected set_compressed");
+ *repeatMode = FSE_repeat_check;
+ return set_compressed;
+}
+
+MEM_STATIC size_t
+ZSTD_buildCTable(void* dst, size_t dstCapacity,
+ FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
+ unsigned* count, U32 max,
+ const BYTE* codeTable, size_t nbSeq,
+ const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+ const FSE_CTable* prevCTable, size_t prevCTableSize,
+ void* workspace, size_t workspaceSize)
+{
+ BYTE* op = (BYTE*)dst;
+ const BYTE* const oend = op + dstCapacity;
+ DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
+
+ switch (type) {
+ case set_rle:
+ CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
+ if (dstCapacity==0) return ERROR(dstSize_tooSmall);
+ *op = codeTable[0];
+ return 1;
+ case set_repeat:
+ memcpy(nextCTable, prevCTable, prevCTableSize);
+ return 0;
+ case set_basic:
+ CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
+ return 0;
+ case set_compressed: {
+ S16 norm[MaxSeq + 1];
+ size_t nbSeq_1 = nbSeq;
+ const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+ if (count[codeTable[nbSeq-1]] > 1) {
+ count[codeTable[nbSeq-1]]--;
+ nbSeq_1--;
+ }
+ assert(nbSeq_1 > 1);
+ CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
+ { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ if (FSE_isError(NCountSize)) return NCountSize;
+ CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
+ return NCountSize;
+ }
+ }
+ default: return assert(0), ERROR(GENERIC);
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_encodeSequences_body(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ BIT_CStream_t blockStream;
+ FSE_CState_t stateMatchLength;
+ FSE_CState_t stateOffsetBits;
+ FSE_CState_t stateLitLength;
+
+ CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */
+ DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)",
+ (int)(blockStream.endPtr - blockStream.startPtr),
+ (unsigned)dstCapacity);
+
+ /* first symbols */
+ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
+ FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
+ FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
+ BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
+ BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
+ if (longOffsets) {
+ U32 const ofBits = ofCodeTable[nbSeq-1];
+ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ if (extraBits) {
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
+ BIT_flushBits(&blockStream);
+ }
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
+ ofBits - extraBits);
+ } else {
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
+ }
+ BIT_flushBits(&blockStream);
+
+ { size_t n;
+ for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
+ BYTE const llCode = llCodeTable[n];
+ BYTE const ofCode = ofCodeTable[n];
+ BYTE const mlCode = mlCodeTable[n];
+ U32 const llBits = LL_bits[llCode];
+ U32 const ofBits = ofCode;
+ U32 const mlBits = ML_bits[mlCode];
+ DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
+ (unsigned)sequences[n].litLength,
+ (unsigned)sequences[n].matchLength + MINMATCH,
+ (unsigned)sequences[n].offset);
+ /* 32b*/ /* 64b*/
+ /* (7)*/ /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
+ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
+ if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
+ if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
+ BIT_flushBits(&blockStream); /* (7)*/
+ BIT_addBits(&blockStream, sequences[n].litLength, llBits);
+ if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
+ BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
+ if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
+ if (longOffsets) {
+ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ if (extraBits) {
+ BIT_addBits(&blockStream, sequences[n].offset, extraBits);
+ BIT_flushBits(&blockStream); /* (7)*/
+ }
+ BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
+ ofBits - extraBits); /* 31 */
+ } else {
+ BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
+ }
+ BIT_flushBits(&blockStream); /* (7)*/
+ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
+ } }
+
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
+ FSE_flushCState(&blockStream, &stateMatchLength);
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
+ FSE_flushCState(&blockStream, &stateOffsetBits);
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
+ FSE_flushCState(&blockStream, &stateLitLength);
+
+ { size_t const streamSize = BIT_closeCStream(&blockStream);
+ if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
+ return streamSize;
+ }
+}
+
+static size_t
+ZSTD_encodeSequences_default(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ return ZSTD_encodeSequences_body(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
+
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_encodeSequences_bmi2(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ return ZSTD_encodeSequences_body(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
+
+#endif
+
+static size_t ZSTD_encodeSequences(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
+{
+ DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
+#if DYNAMIC_BMI2
+ if (bmi2) {
+ return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+ }
+#endif
+ (void)bmi2;
+ return ZSTD_encodeSequences_default(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
+
+/* ZSTD_compressSequences_internal():
+ * actually compresses both literals and sequences */
+MEM_STATIC size_t
+ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ void* workspace, size_t wkspSize,
+ const int bmi2)
+{
+ const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
+ ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+ unsigned count[MaxSeq+1];
+ FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
+ FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
+ FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
+ U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
+ const seqDef* const sequences = seqStorePtr->sequencesStart;
+ const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ const BYTE* const llCodeTable = seqStorePtr->llCode;
+ const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart;
+ size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
+ BYTE* seqHead;
+ BYTE* lastNCount = NULL;
+
+ ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+ DEBUGLOG(5, "ZSTD_compressSequences_internal");
+
+ /* Compress literals */
+ { const BYTE* const literals = seqStorePtr->litStart;
+ size_t const litSize = seqStorePtr->lit - literals;
+ int const disableLiteralCompression = (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0);
+ size_t const cSize = ZSTD_compressLiterals(
+ &prevEntropy->huf, &nextEntropy->huf,
+ cctxParams->cParams.strategy, disableLiteralCompression,
+ op, dstCapacity,
+ literals, litSize,
+ workspace, wkspSize,
+ bmi2);
+ if (ZSTD_isError(cSize))
+ return cSize;
+ assert(cSize <= dstCapacity);
+ op += cSize;
+ }
+
+ /* Sequences Header */
+ if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall);
+ if (nbSeq < 0x7F)
+ *op++ = (BYTE)nbSeq;
+ else if (nbSeq < LONGNBSEQ)
+ op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
+ else
+ op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
+ if (nbSeq==0) {
+ /* Copy the old tables over as if we repeated them */
+ memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
+ return op - ostart;
+ }
+
+ /* seqHead : flags for FSE encoding type */
+ seqHead = op++;
+
+ /* convert length/distances into codes */
+ ZSTD_seqToCodes(seqStorePtr);
+ /* build CTable for Literal Lengths */
+ { unsigned max = MaxLL;
+ size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ DEBUGLOG(5, "Building LL table");
+ nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
+ LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ LLFSELog, prevEntropy->fse.litlengthCTable,
+ LL_defaultNorm, LL_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(set_basic < set_compressed && set_rle < set_compressed);
+ assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
+ count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
+ prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable),
+ workspace, wkspSize);
+ if (ZSTD_isError(countSize)) return countSize;
+ if (LLtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ } }
+ /* build CTable for Offsets */
+ { unsigned max = MaxOff;
+ size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+ ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+ DEBUGLOG(5, "Building OF table");
+ nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
+ Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ OffFSELog, prevEntropy->fse.offcodeCTable,
+ OF_defaultNorm, OF_defaultNormLog,
+ defaultPolicy, strategy);
+ assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
+ count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+ prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable),
+ workspace, wkspSize);
+ if (ZSTD_isError(countSize)) return countSize;
+ if (Offtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ } }
+ /* build CTable for MatchLengths */
+ { unsigned max = MaxML;
+ size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+ nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
+ MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ MLFSELog, prevEntropy->fse.matchlengthCTable,
+ ML_defaultNorm, ML_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
+ count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
+ prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable),
+ workspace, wkspSize);
+ if (ZSTD_isError(countSize)) return countSize;
+ if (MLtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ } }
+
+ *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+
+ { size_t const bitstreamSize = ZSTD_encodeSequences(
+ op, oend - op,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq,
+ longOffsets, bmi2);
+ if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
+ op += bitstreamSize;
+ /* zstd versions <= 1.3.4 mistakenly report corruption when
+ * FSE_readNCount() recieves a buffer < 4 bytes.
+ * Fixed by https://github.com/facebook/zstd/pull/1146.
+ * This can happen when the last set_compressed table present is 2
+ * bytes and the bitstream is only one byte.
+ * In this exceedingly rare case, we will simply emit an uncompressed
+ * block, since it isn't worth optimizing.
+ */
+ if (lastNCount && (op - lastNCount) < 4) {
+ /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+ assert(op - lastNCount == 3);
+ DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
+ "emitting an uncompressed block.");
+ return 0;
+ }
+ }
+
+ DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
+ return op - ostart;
+}
+
+MEM_STATIC size_t
+ZSTD_compressSequences(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ size_t srcSize,
+ void* workspace, size_t wkspSize,
+ int bmi2)
+{
+ size_t const cSize = ZSTD_compressSequences_internal(
+ seqStorePtr, prevEntropy, nextEntropy, cctxParams,
+ dst, dstCapacity,
+ workspace, wkspSize, bmi2);
+ if (cSize == 0) return 0;
+ /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
+ * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
+ */
+ if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
+ return 0; /* block not compressed */
+ if (ZSTD_isError(cSize)) return cSize;
+
+ /* Check compressibility */
+ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
+ if (cSize >= maxCSize) return 0; /* block not compressed */
+ }
+
+ return cSize;
+}
+
+/* ZSTD_selectBlockCompressor() :
+ * Not static, but internal use only (used by long distance matcher)
+ * assumption : strat is a valid strategy */
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
+{
+ static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
+ { ZSTD_compressBlock_fast /* default for 0 */,
+ ZSTD_compressBlock_fast,
+ ZSTD_compressBlock_doubleFast,
+ ZSTD_compressBlock_greedy,
+ ZSTD_compressBlock_lazy,
+ ZSTD_compressBlock_lazy2,
+ ZSTD_compressBlock_btlazy2,
+ ZSTD_compressBlock_btopt,
+ ZSTD_compressBlock_btultra,
+ ZSTD_compressBlock_btultra2 },
+ { ZSTD_compressBlock_fast_extDict /* default for 0 */,
+ ZSTD_compressBlock_fast_extDict,
+ ZSTD_compressBlock_doubleFast_extDict,
+ ZSTD_compressBlock_greedy_extDict,
+ ZSTD_compressBlock_lazy_extDict,
+ ZSTD_compressBlock_lazy2_extDict,
+ ZSTD_compressBlock_btlazy2_extDict,
+ ZSTD_compressBlock_btopt_extDict,
+ ZSTD_compressBlock_btultra_extDict,
+ ZSTD_compressBlock_btultra_extDict },
+ { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */,
+ ZSTD_compressBlock_fast_dictMatchState,
+ ZSTD_compressBlock_doubleFast_dictMatchState,
+ ZSTD_compressBlock_greedy_dictMatchState,
+ ZSTD_compressBlock_lazy_dictMatchState,
+ ZSTD_compressBlock_lazy2_dictMatchState,
+ ZSTD_compressBlock_btlazy2_dictMatchState,
+ ZSTD_compressBlock_btopt_dictMatchState,
+ ZSTD_compressBlock_btultra_dictMatchState,
+ ZSTD_compressBlock_btultra_dictMatchState }
+ };
+ ZSTD_blockCompressor selectedCompressor;
+ ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
+
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+ selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+ assert(selectedCompressor != NULL);
+ return selectedCompressor;
+}
+
+static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
+ const BYTE* anchor, size_t lastLLSize)
+{
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
+ seqStorePtr->lit += lastLLSize;
+}
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr)
+{
+ ssPtr->lit = ssPtr->litStart;
+ ssPtr->sequences = ssPtr->sequencesStart;
+ ssPtr->longLengthID = 0;
+}
+
+static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ ZSTD_matchState_t* const ms = &zc->blockState.matchState;
+ size_t cSize;
+ DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
+ (unsigned)dstCapacity, (unsigned)ms->window.dictLimit, (unsigned)ms->nextToUpdate);
+ assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+
+ /* Assert that we have correctly flushed the ctx params into the ms's copy */
+ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
+
+ if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
+ ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
+ cSize = 0;
+ goto out; /* don't even attempt compression below a certain srcSize */
+ }
+ ZSTD_resetSeqStore(&(zc->seqStore));
+ ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; /* required for optimal parser to read stats from dictionary */
+
+ /* a gap between an attached dict and the current window is not safe,
+ * they must remain adjacent,
+ * and when that stops being the case, the dict must be unset */
+ assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
+
+ /* limited update after a very long match */
+ { const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const U32 current = (U32)(istart-base);
+ if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */
+ if (current > ms->nextToUpdate + 384)
+ ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
+ }
+
+ /* select and store sequences */
+ { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
+ size_t lastLLSize;
+ { int i;
+ for (i = 0; i < ZSTD_REP_NUM; ++i)
+ zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
+ }
+ if (zc->externSeqStore.pos < zc->externSeqStore.size) {
+ assert(!zc->appliedParams.ldmParams.enableLdm);
+ /* Updates ldmSeqStore.pos */
+ lastLLSize =
+ ZSTD_ldm_blockCompress(&zc->externSeqStore,
+ ms, &zc->seqStore,
+ zc->blockState.nextCBlock->rep,
+ src, srcSize);
+ assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
+ } else if (zc->appliedParams.ldmParams.enableLdm) {
+ rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
+
+ ldmSeqStore.seq = zc->ldmSequences;
+ ldmSeqStore.capacity = zc->maxNbLdmSequences;
+ /* Updates ldmSeqStore.size */
+ CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
+ &zc->appliedParams.ldmParams,
+ src, srcSize));
+ /* Updates ldmSeqStore.pos */
+ lastLLSize =
+ ZSTD_ldm_blockCompress(&ldmSeqStore,
+ ms, &zc->seqStore,
+ zc->blockState.nextCBlock->rep,
+ src, srcSize);
+ assert(ldmSeqStore.pos == ldmSeqStore.size);
+ } else { /* not long range mode */
+ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
+ lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
+ }
+ { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
+ ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
+ } }
+
+ /* encode sequences and literals */
+ cSize = ZSTD_compressSequences(&zc->seqStore,
+ &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
+ &zc->appliedParams,
+ dst, dstCapacity,
+ srcSize,
+ zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+ zc->bmi2);
+
+out:
+ if (!ZSTD_isError(cSize) && cSize != 0) {
+ /* confirm repcodes and entropy tables when emitting a compressed block */
+ ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
+ zc->blockState.prevCBlock = zc->blockState.nextCBlock;
+ zc->blockState.nextCBlock = tmp;
+ }
+ /* We check that dictionaries have offset codes available for the first
+ * block. After the first block, the offcode table might not have large
+ * enough codes to represent the offsets in the data.
+ */
+ if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+ zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+ return cSize;
+}
+
+
+/*! ZSTD_compress_frameChunk() :
+* Compress a chunk of data into one or multiple blocks.
+* All blocks will be terminated, all input will be consumed.
+* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
+* Frame is supposed already started (header already produced)
+* @return : compressed size, or an error code
+*/
+static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 lastFrameChunk)
+{
+ size_t blockSize = cctx->blockSize;
+ size_t remaining = srcSize;
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* op = ostart;
+ U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
+ assert(cctx->appliedParams.cParams.windowLog <= 31);
+
+ DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
+ if (cctx->appliedParams.fParams.checksumFlag && srcSize)
+ XXH64_update(&cctx->xxhState, src, srcSize);
+
+ while (remaining) {
+ ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+ U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
+
+ if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
+ return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
+ if (remaining < blockSize) blockSize = remaining;
+
+ if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) {
+ U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
+ U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
+ ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
+ ZSTD_reduceIndex(cctx, correction);
+ if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+ else ms->nextToUpdate -= correction;
+ ms->loadedDictEnd = 0;
+ ms->dictMatchState = NULL;
+ }
+ ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
+ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
+
+ { size_t cSize = ZSTD_compressBlock_internal(cctx,
+ op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
+ ip, blockSize);
+ if (ZSTD_isError(cSize)) return cSize;
+
+ if (cSize == 0) { /* block is not compressible */
+ cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
+ if (ZSTD_isError(cSize)) return cSize;
+ } else {
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+ MEM_writeLE24(op, cBlockHeader24);
+ cSize += ZSTD_blockHeaderSize;
+ }
+
+ ip += blockSize;
+ assert(remaining >= blockSize);
+ remaining -= blockSize;
+ op += cSize;
+ assert(dstCapacity >= cSize);
+ dstCapacity -= cSize;
+ DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
+ (unsigned)cSize);
+ } }
+
+ if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
+ return op-ostart;
+}
+
+
+static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
+ ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID)
+{ BYTE* const op = (BYTE*)dst;
+ U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
+ U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
+ U32 const checksumFlag = params.fParams.checksumFlag>0;
+ U32 const windowSize = (U32)1 << params.cParams.windowLog;
+ U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
+ BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
+ U32 const fcsCode = params.fParams.contentSizeFlag ?
+ (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
+ BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
+ size_t pos=0;
+
+ assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
+ if (dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX) return ERROR(dstSize_tooSmall);
+ DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
+ !params.fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
+
+ if (params.format == ZSTD_f_zstd1) {
+ MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
+ pos = 4;
+ }
+ op[pos++] = frameHeaderDecriptionByte;
+ if (!singleSegment) op[pos++] = windowLogByte;
+ switch(dictIDSizeCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : break;
+ case 1 : op[pos] = (BYTE)(dictID); pos++; break;
+ case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
+ case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
+ }
+ switch(fcsCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
+ case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
+ case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
+ case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
+ }
+ return pos;
+}
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ * or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
+{
+ if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall);
+ { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
+ MEM_writeLE24(dst, cBlockHeader24);
+ return ZSTD_blockHeaderSize;
+ }
+}
+
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
+{
+ if (cctx->stage != ZSTDcs_init)
+ return ERROR(stage_wrong);
+ if (cctx->appliedParams.ldmParams.enableLdm)
+ return ERROR(parameter_unsupported);
+ cctx->externSeqStore.seq = seq;
+ cctx->externSeqStore.size = nbSeq;
+ cctx->externSeqStore.capacity = nbSeq;
+ cctx->externSeqStore.pos = 0;
+ return 0;
+}
+
+
+static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 frame, U32 lastFrameChunk)
+{
+ ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+ size_t fhSize = 0;
+
+ DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
+ cctx->stage, (unsigned)srcSize);
+ if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
+
+ if (frame && (cctx->stage==ZSTDcs_init)) {
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
+ cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
+ if (ZSTD_isError(fhSize)) return fhSize;
+ dstCapacity -= fhSize;
+ dst = (char*)dst + fhSize;
+ cctx->stage = ZSTDcs_ongoing;
+ }
+
+ if (!srcSize) return fhSize; /* do not generate an empty block if no input */
+
+ if (!ZSTD_window_update(&ms->window, src, srcSize)) {
+ ms->nextToUpdate = ms->window.dictLimit;
+ }
+ if (cctx->appliedParams.ldmParams.enableLdm) {
+ ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
+ }
+
+ if (!frame) {
+ /* overflow check and correction for block mode */
+ if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) {
+ U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
+ U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src);
+ ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
+ ZSTD_reduceIndex(cctx, correction);
+ if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+ else ms->nextToUpdate -= correction;
+ ms->loadedDictEnd = 0;
+ ms->dictMatchState = NULL;
+ }
+ }
+
+ DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
+ { size_t const cSize = frame ?
+ ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
+ ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
+ if (ZSTD_isError(cSize)) return cSize;
+ cctx->consumedSrcSize += srcSize;
+ cctx->producedCSize += (cSize + fhSize);
+ assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+ if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+ if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) {
+ DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u",
+ (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize);
+ return ERROR(srcSize_wrong);
+ }
+ }
+ return cSize + fhSize;
+ }
+}
+
+size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
+ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
+}
+
+
+size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
+{
+ ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
+ assert(!ZSTD_checkCParams(cParams));
+ return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
+}
+
+size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
+ if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
+
+ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
+}
+
+/*! ZSTD_loadDictionaryContent() :
+ * @return : 0, or an error code
+ */
+static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
+ ZSTD_CCtx_params const* params,
+ const void* src, size_t srcSize,
+ ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const BYTE* const ip = (const BYTE*) src;
+ const BYTE* const iend = ip + srcSize;
+
+ ZSTD_window_update(&ms->window, src, srcSize);
+ ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
+
+ /* Assert that we the ms params match the params we're being given */
+ ZSTD_assertEqualCParams(params->cParams, ms->cParams);
+
+ if (srcSize <= HASH_READ_SIZE) return 0;
+
+ switch(params->cParams.strategy)
+ {
+ case ZSTD_fast:
+ ZSTD_fillHashTable(ms, iend, dtlm);
+ break;
+ case ZSTD_dfast:
+ ZSTD_fillDoubleHashTable(ms, iend, dtlm);
+ break;
+
+ case ZSTD_greedy:
+ case ZSTD_lazy:
+ case ZSTD_lazy2:
+ if (srcSize >= HASH_READ_SIZE)
+ ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE);
+ break;
+
+ case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
+ case ZSTD_btopt:
+ case ZSTD_btultra:
+ case ZSTD_btultra2:
+ if (srcSize >= HASH_READ_SIZE)
+ ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend);
+ break;
+
+ default:
+ assert(0); /* not possible : not a valid strategy id */
+ }
+
+ ms->nextToUpdate = (U32)(iend - ms->window.base);
+ return 0;
+}
+
+
+/* Dictionaries that assign zero probability to symbols that show up causes problems
+ when FSE encoding. Refuse dictionaries that assign zero probability to symbols
+ that we may encounter during compression.
+ NOTE: This behavior is not standard and could be improved in the future. */
+static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
+ U32 s;
+ if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
+ for (s = 0; s <= maxSymbolValue; ++s) {
+ if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
+ }
+ return 0;
+}
+
+
+/* Dictionary format :
+ * See :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+ */
+/*! ZSTD_loadZstdDictionary() :
+ * @return : dictID, or an error code
+ * assumptions : magic number supposed already checked
+ * dictSize supposed > 8
+ */
+static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
+ ZSTD_matchState_t* ms,
+ ZSTD_CCtx_params const* params,
+ const void* dict, size_t dictSize,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ void* workspace)
+{
+ const BYTE* dictPtr = (const BYTE*)dict;
+ const BYTE* const dictEnd = dictPtr + dictSize;
+ short offcodeNCount[MaxOff+1];
+ unsigned offcodeMaxValue = MaxOff;
+ size_t dictID;
+
+ ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+ assert(dictSize > 8);
+ assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
+
+ dictPtr += 4; /* skip magic number */
+ dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
+ dictPtr += 4;
+
+ { unsigned maxSymbolValue = 255;
+ size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
+ if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
+ if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
+ dictPtr += hufHeaderSize;
+ }
+
+ { unsigned offcodeLog;
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
+ if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
+ /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
+ /* fill all offset symbols to avoid garbage at end of table */
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.offcodeCTable,
+ offcodeNCount, MaxOff, offcodeLog,
+ workspace, HUF_WORKSPACE_SIZE),
+ dictionary_corrupted);
+ dictPtr += offcodeHeaderSize;
+ }
+
+ { short matchlengthNCount[MaxML+1];
+ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
+ if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
+ /* Every match length code must have non-zero probability */
+ CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.matchlengthCTable,
+ matchlengthNCount, matchlengthMaxValue, matchlengthLog,
+ workspace, HUF_WORKSPACE_SIZE),
+ dictionary_corrupted);
+ dictPtr += matchlengthHeaderSize;
+ }
+
+ { short litlengthNCount[MaxLL+1];
+ unsigned litlengthMaxValue = MaxLL, litlengthLog;
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
+ if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
+ /* Every literal length code must have non-zero probability */
+ CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.litlengthCTable,
+ litlengthNCount, litlengthMaxValue, litlengthLog,
+ workspace, HUF_WORKSPACE_SIZE),
+ dictionary_corrupted);
+ dictPtr += litlengthHeaderSize;
+ }
+
+ if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
+ bs->rep[0] = MEM_readLE32(dictPtr+0);
+ bs->rep[1] = MEM_readLE32(dictPtr+4);
+ bs->rep[2] = MEM_readLE32(dictPtr+8);
+ dictPtr += 12;
+
+ { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
+ U32 offcodeMax = MaxOff;
+ if (dictContentSize <= ((U32)-1) - 128 KB) {
+ U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
+ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
+ }
+ /* All offset values <= dictContentSize + 128 KB must be representable */
+ CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
+ /* All repCodes must be <= dictContentSize and != 0*/
+ { U32 u;
+ for (u=0; u<3; u++) {
+ if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
+ if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
+ } }
+
+ bs->entropy.huf.repeatMode = HUF_repeat_valid;
+ bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
+ bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
+ bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
+ CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm));
+ return dictID;
+ }
+}
+
+/** ZSTD_compress_insertDictionary() :
+* @return : dictID, or an error code */
+static size_t
+ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
+ ZSTD_matchState_t* ms,
+ const ZSTD_CCtx_params* params,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ void* workspace)
+{
+ DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
+ if ((dict==NULL) || (dictSize<=8)) return 0;
+
+ ZSTD_reset_compressedBlockState(bs);
+
+ /* dict restricted modes */
+ if (dictContentType == ZSTD_dct_rawContent)
+ return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
+
+ if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
+ if (dictContentType == ZSTD_dct_auto) {
+ DEBUGLOG(4, "raw content dictionary detected");
+ return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
+ }
+ if (dictContentType == ZSTD_dct_fullDict)
+ return ERROR(dictionary_wrong);
+ assert(0); /* impossible */
+ }
+
+ /* dict as full zstd dictionary */
+ return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace);
+}
+
+/*! ZSTD_compressBegin_internal() :
+ * @return : 0, or an error code */
+static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params, U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog);
+ /* params are supposed to be fully validated at this point */
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+
+ if (cdict && cdict->dictContentSize>0) {
+ return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
+ }
+
+ CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_continue, zbuff) );
+ {
+ size_t const dictID = ZSTD_compress_insertDictionary(
+ cctx->blockState.prevCBlock, &cctx->blockState.matchState,
+ &params, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace);
+ if (ZSTD_isError(dictID)) return dictID;
+ assert(dictID <= (size_t)(U32)-1);
+ cctx->dictID = (U32)dictID;
+ }
+ return 0;
+}
+
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog);
+ /* compression parameters verification and optimization */
+ CHECK_F( ZSTD_checkCParams(params.cParams) );
+ return ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, dictContentType, dtlm,
+ cdict,
+ params, pledgedSrcSize,
+ ZSTDb_not_buffered);
+}
+
+/*! ZSTD_compressBegin_advanced() :
+* @return : 0, or an error code */
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+ return ZSTD_compressBegin_advanced_internal(cctx,
+ dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
+ NULL /*cdict*/,
+ cctxParams, pledgedSrcSize);
+}
+
+size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+ DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
+ return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+ cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
+}
+
+size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
+{
+ return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
+}
+
+
+/*! ZSTD_writeEpilogue() :
+* Ends a frame.
+* @return : nb of bytes written into dst (or an error code) */
+static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
+{
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* op = ostart;
+ size_t fhSize = 0;
+
+ DEBUGLOG(4, "ZSTD_writeEpilogue");
+ if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
+
+ /* special case : empty frame */
+ if (cctx->stage == ZSTDcs_init) {
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
+ if (ZSTD_isError(fhSize)) return fhSize;
+ dstCapacity -= fhSize;
+ op += fhSize;
+ cctx->stage = ZSTDcs_ongoing;
+ }
+
+ if (cctx->stage != ZSTDcs_ending) {
+ /* write one last empty block, make it the "last" block */
+ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
+ if (dstCapacity<4) return ERROR(dstSize_tooSmall);
+ MEM_writeLE32(op, cBlockHeader24);
+ op += ZSTD_blockHeaderSize;
+ dstCapacity -= ZSTD_blockHeaderSize;
+ }
+
+ if (cctx->appliedParams.fParams.checksumFlag) {
+ U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
+ if (dstCapacity<4) return ERROR(dstSize_tooSmall);
+ DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
+ MEM_writeLE32(op, checksum);
+ op += 4;
+ }
+
+ cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
+ return op-ostart;
+}
+
+size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ size_t endResult;
+ size_t const cSize = ZSTD_compressContinue_internal(cctx,
+ dst, dstCapacity, src, srcSize,
+ 1 /* frame mode */, 1 /* last chunk */);
+ if (ZSTD_isError(cSize)) return cSize;
+ endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
+ if (ZSTD_isError(endResult)) return endResult;
+ assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+ if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+ DEBUGLOG(4, "end of frame : controlling src size");
+ if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
+ DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
+ (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize);
+ return ERROR(srcSize_wrong);
+ } }
+ return cSize + endResult;
+}
+
+
+static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_parameters params)
+{
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+ DEBUGLOG(4, "ZSTD_compress_internal");
+ return ZSTD_compress_advanced_internal(cctx,
+ dst, dstCapacity,
+ src, srcSize,
+ dict, dictSize,
+ cctxParams);
+}
+
+size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_parameters params)
+{
+ DEBUGLOG(4, "ZSTD_compress_advanced");
+ CHECK_F(ZSTD_checkCParams(params.cParams));
+ return ZSTD_compress_internal(cctx,
+ dst, dstCapacity,
+ src, srcSize,
+ dict, dictSize,
+ params);
+}
+
+/* Internal */
+size_t ZSTD_compress_advanced_internal(
+ ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_CCtx_params params)
+{
+ DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
+ CHECK_F( ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+ params, srcSize, ZSTDb_not_buffered) );
+ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize,
+ int compressionLevel)
+{
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0);
+ ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+ assert(params.fParams.contentSizeFlag == 1);
+ return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams);
+}
+
+size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel)
+{
+ DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
+ assert(cctx != NULL);
+ return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
+}
+
+size_t ZSTD_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel)
+{
+ size_t result;
+ ZSTD_CCtx ctxBody;
+ ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
+ result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
+ ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
+ return result;
+}
+
+
+/* ===== Dictionary API ===== */
+
+/*! ZSTD_estimateCDictSize_advanced() :
+ * Estimate amount of memory that will be needed to create a dictionary with following arguments */
+size_t ZSTD_estimateCDictSize_advanced(
+ size_t dictSize, ZSTD_compressionParameters cParams,
+ ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+ DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
+ return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
+ + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+}
+
+size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+ return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
+}
+
+size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
+{
+ if (cdict==NULL) return 0; /* support sizeof on NULL */
+ DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
+ return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
+}
+
+static size_t ZSTD_initCDict_internal(
+ ZSTD_CDict* cdict,
+ const void* dictBuffer, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams)
+{
+ DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
+ assert(!ZSTD_checkCParams(cParams));
+ cdict->matchState.cParams = cParams;
+ if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
+ cdict->dictBuffer = NULL;
+ cdict->dictContent = dictBuffer;
+ } else {
+ void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem);
+ cdict->dictBuffer = internalBuffer;
+ cdict->dictContent = internalBuffer;
+ if (!internalBuffer) return ERROR(memory_allocation);
+ memcpy(internalBuffer, dictBuffer, dictSize);
+ }
+ cdict->dictContentSize = dictSize;
+
+ /* Reset the state to no dictionary */
+ ZSTD_reset_compressedBlockState(&cdict->cBlockState);
+ { void* const end = ZSTD_reset_matchState(
+ &cdict->matchState,
+ (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32,
+ &cParams, ZSTDcrp_continue, /* forCCtx */ 0);
+ assert(end == (char*)cdict->workspace + cdict->workspaceSize);
+ (void)end;
+ }
+ /* (Maybe) load the dictionary
+ * Skips loading the dictionary if it is <= 8 bytes.
+ */
+ { ZSTD_CCtx_params params;
+ memset(&params, 0, sizeof(params));
+ params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ params.fParams.contentSizeFlag = 1;
+ params.cParams = cParams;
+ { size_t const dictID = ZSTD_compress_insertDictionary(
+ &cdict->cBlockState, &cdict->matchState, &params,
+ cdict->dictContent, cdict->dictContentSize,
+ dictContentType, ZSTD_dtlm_full, cdict->workspace);
+ if (ZSTD_isError(dictID)) return dictID;
+ assert(dictID <= (size_t)(U32)-1);
+ cdict->dictID = (U32)dictID;
+ }
+ }
+
+ return 0;
+}
+
+ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
+{
+ DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
+ size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+ void* const workspace = ZSTD_malloc(workspaceSize, customMem);
+
+ if (!cdict || !workspace) {
+ ZSTD_free(cdict, customMem);
+ ZSTD_free(workspace, customMem);
+ return NULL;
+ }
+ cdict->customMem = customMem;
+ cdict->workspace = workspace;
+ cdict->workspaceSize = workspaceSize;
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+ dictBuffer, dictSize,
+ dictLoadMethod, dictContentType,
+ cParams) )) {
+ ZSTD_freeCDict(cdict);
+ return NULL;
+ }
+
+ return cdict;
+ }
+}
+
+ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+ return ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byCopy, ZSTD_dct_auto,
+ cParams, ZSTD_defaultCMem);
+}
+
+ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+ return ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byRef, ZSTD_dct_auto,
+ cParams, ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
+{
+ if (cdict==NULL) return 0; /* support free on NULL */
+ { ZSTD_customMem const cMem = cdict->customMem;
+ ZSTD_free(cdict->workspace, cMem);
+ ZSTD_free(cdict->dictBuffer, cMem);
+ ZSTD_free(cdict, cMem);
+ return 0;
+ }
+}
+
+/*! ZSTD_initStaticCDict_advanced() :
+ * Generate a digested dictionary in provided memory area.
+ * workspace: The memory area to emplace the dictionary into.
+ * Provided pointer must 8-bytes aligned.
+ * It must outlive dictionary usage.
+ * workspaceSize: Use ZSTD_estimateCDictSize()
+ * to determine how large workspace must be.
+ * cParams : use ZSTD_getCParams() to transform a compression level
+ * into its relevants cParams.
+ * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
+ * Note : there is no corresponding "free" function.
+ * Since workspace was allocated externally, it must be freed externally.
+ */
+const ZSTD_CDict* ZSTD_initStaticCDict(
+ void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams)
+{
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+ size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
+ + HUF_WORKSPACE_SIZE + matchStateSize;
+ ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
+ void* ptr;
+ if ((size_t)workspace & 7) return NULL; /* 8-aligned */
+ DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
+ (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
+ if (workspaceSize < neededSize) return NULL;
+
+ if (dictLoadMethod == ZSTD_dlm_byCopy) {
+ memcpy(cdict+1, dict, dictSize);
+ dict = cdict+1;
+ ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
+ } else {
+ ptr = cdict+1;
+ }
+ cdict->workspace = ptr;
+ cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize;
+
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+ dict, dictSize,
+ ZSTD_dlm_byRef, dictContentType,
+ cParams) ))
+ return NULL;
+
+ return cdict;
+}
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
+{
+ assert(cdict != NULL);
+ return cdict->matchState.cParams;
+}
+
+/* ZSTD_compressBegin_usingCDict_advanced() :
+ * cdict must be != NULL */
+size_t ZSTD_compressBegin_usingCDict_advanced(
+ ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
+ ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
+ if (cdict==NULL) return ERROR(dictionary_wrong);
+ { ZSTD_CCtx_params params = cctx->requestedParams;
+ params.cParams = ZSTD_getCParamsFromCDict(cdict);
+ /* Increase window log to fit the entire dictionary and source if the
+ * source size is known. Limit the increase to 19, which is the
+ * window log for compression level 1 with the largest source size.
+ */
+ if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
+ U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
+ params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
+ }
+ params.fParams = fParams;
+ return ZSTD_compressBegin_internal(cctx,
+ NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
+ cdict,
+ params, pledgedSrcSize,
+ ZSTDb_not_buffered);
+ }
+}
+
+/* ZSTD_compressBegin_usingCDict() :
+ * pledgedSrcSize=0 means "unknown"
+ * if pledgedSrcSize>0, it will enable contentSizeFlag */
+size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+ ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
+ return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
+{
+ CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
+ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+/*! ZSTD_compress_usingCDict() :
+ * Compression using a digested Dictionary.
+ * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
+ * Note that compression parameters are decided at CDict creation time
+ * while frame parameters are hardcoded */
+size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict)
+{
+ ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+}
+
+
+
+/* ******************************************************************
+* Streaming
+********************************************************************/
+
+ZSTD_CStream* ZSTD_createCStream(void)
+{
+ DEBUGLOG(3, "ZSTD_createCStream");
+ return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
+{
+ return ZSTD_initStaticCCtx(workspace, workspaceSize);
+}
+
+ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
+{ /* CStream and CCtx are now same object */
+ return ZSTD_createCCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
+{
+ return ZSTD_freeCCtx(zcs); /* same object */
+}
+
+
+
+/*====== Initialization ======*/
+
+size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_CStreamOutSize(void)
+{
+ return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
+}
+
+static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
+ const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
+ const ZSTD_CDict* const cdict,
+ ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_resetCStream_internal");
+ /* Finalize the compression parameters */
+ params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
+ /* params are supposed to be fully validated at this point */
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+
+ CHECK_F( ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, dictContentType, ZSTD_dtlm_fast,
+ cdict,
+ params, pledgedSrcSize,
+ ZSTDb_buffered) );
+
+ cctx->inToCompress = 0;
+ cctx->inBuffPos = 0;
+ cctx->inBuffTarget = cctx->blockSize
+ + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
+ cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
+ cctx->streamStage = zcss_load;
+ cctx->frameEnded = 0;
+ return 0; /* ready to go */
+}
+
+/* ZSTD_resetCStream():
+ * pledgedSrcSize == 0 means "unknown" */
+size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
+{
+ ZSTD_CCtx_params params = zcs->requestedParams;
+ DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
+ if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ params.fParams.contentSizeFlag = 1;
+ return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
+}
+
+/*! ZSTD_initCStream_internal() :
+ * Note : for lib/compress only. Used by zstdmt_compress.c.
+ * Assumption 1 : params are valid
+ * Assumption 2 : either dict, or cdict, is defined, not both */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_internal");
+ params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+
+ if (dict && dictSize >= 8) {
+ DEBUGLOG(4, "loading dictionary of size %u", (unsigned)dictSize);
+ if (zcs->staticSize) { /* static CCtx : never uses malloc */
+ /* incompatible with internal cdict creation */
+ return ERROR(memory_allocation);
+ }
+ ZSTD_freeCDict(zcs->cdictLocal);
+ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byCopy, ZSTD_dct_auto,
+ params.cParams, zcs->customMem);
+ zcs->cdict = zcs->cdictLocal;
+ if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
+ } else {
+ if (cdict) {
+ params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict; it includes windowLog */
+ }
+ ZSTD_freeCDict(zcs->cdictLocal);
+ zcs->cdictLocal = NULL;
+ zcs->cdict = cdict;
+ }
+
+ return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
+}
+
+/* ZSTD_initCStream_usingCDict_advanced() :
+ * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
+size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
+ const ZSTD_CDict* cdict,
+ ZSTD_frameParameters fParams,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
+ if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */
+ { ZSTD_CCtx_params params = zcs->requestedParams;
+ params.cParams = ZSTD_getCParamsFromCDict(cdict);
+ params.fParams = fParams;
+ return ZSTD_initCStream_internal(zcs,
+ NULL, 0, cdict,
+ params, pledgedSrcSize);
+ }
+}
+
+/* note : cdict must outlive compression session */
+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
+{
+ ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ };
+ DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
+ return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */
+}
+
+
+/* ZSTD_initCStream_advanced() :
+ * pledgedSrcSize must be exact.
+ * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
+ * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
+size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u",
+ (unsigned)pledgedSrcSize, params.fParams.contentSizeFlag);
+ CHECK_F( ZSTD_checkCParams(params.cParams) );
+ if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */
+ zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
+ return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, zcs->requestedParams, pledgedSrcSize);
+}
+
+size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel);
+ return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, zcs->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
+{
+ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */
+ ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel);
+ return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, zcs->requestedParams, pledgedSrcSize);
+}
+
+size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
+{
+ DEBUGLOG(4, "ZSTD_initCStream");
+ return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+/*====== Compression ======*/
+
+static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
+{
+ size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
+ if (hintInSize==0) hintInSize = cctx->blockSize;
+ return hintInSize;
+}
+
+static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ size_t const length = MIN(dstCapacity, srcSize);
+ if (length) memcpy(dst, src, length);
+ return length;
+}
+
+/** ZSTD_compressStream_generic():
+ * internal function for all *compressStream*() variants
+ * non-static, because can be called from zstdmt_compress.c
+ * @return : hint size for next input */
+size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective const flushMode)
+{
+ const char* const istart = (const char*)input->src;
+ const char* const iend = istart + input->size;
+ const char* ip = istart + input->pos;
+ char* const ostart = (char*)output->dst;
+ char* const oend = ostart + output->size;
+ char* op = ostart + output->pos;
+ U32 someMoreWork = 1;
+
+ /* check expectations */
+ DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
+ assert(zcs->inBuff != NULL);
+ assert(zcs->inBuffSize > 0);
+ assert(zcs->outBuff != NULL);
+ assert(zcs->outBuffSize > 0);
+ assert(output->pos <= output->size);
+ assert(input->pos <= input->size);
+
+ while (someMoreWork) {
+ switch(zcs->streamStage)
+ {
+ case zcss_init:
+ /* call ZSTD_initCStream() first ! */
+ return ERROR(init_missing);
+
+ case zcss_load:
+ if ( (flushMode == ZSTD_e_end)
+ && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
+ && (zcs->inBuffPos == 0) ) {
+ /* shortcut to compression pass directly into output buffer */
+ size_t const cSize = ZSTD_compressEnd(zcs,
+ op, oend-op, ip, iend-ip);
+ DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
+ if (ZSTD_isError(cSize)) return cSize;
+ ip = iend;
+ op += cSize;
+ zcs->frameEnded = 1;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ someMoreWork = 0; break;
+ }
+ /* complete loading into inBuffer */
+ { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
+ size_t const loaded = ZSTD_limitCopy(
+ zcs->inBuff + zcs->inBuffPos, toLoad,
+ ip, iend-ip);
+ zcs->inBuffPos += loaded;
+ ip += loaded;
+ if ( (flushMode == ZSTD_e_continue)
+ && (zcs->inBuffPos < zcs->inBuffTarget) ) {
+ /* not enough input to fill full block : stop here */
+ someMoreWork = 0; break;
+ }
+ if ( (flushMode == ZSTD_e_flush)
+ && (zcs->inBuffPos == zcs->inToCompress) ) {
+ /* empty */
+ someMoreWork = 0; break;
+ }
+ }
+ /* compress current block (note : this stage cannot be stopped in the middle) */
+ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
+ { void* cDst;
+ size_t cSize;
+ size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
+ size_t oSize = oend-op;
+ unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
+ if (oSize >= ZSTD_compressBound(iSize))
+ cDst = op; /* compress into output buffer, to skip flush stage */
+ else
+ cDst = zcs->outBuff, oSize = zcs->outBuffSize;
+ cSize = lastBlock ?
+ ZSTD_compressEnd(zcs, cDst, oSize,
+ zcs->inBuff + zcs->inToCompress, iSize) :
+ ZSTD_compressContinue(zcs, cDst, oSize,
+ zcs->inBuff + zcs->inToCompress, iSize);
+ if (ZSTD_isError(cSize)) return cSize;
+ zcs->frameEnded = lastBlock;
+ /* prepare next block */
+ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
+ if (zcs->inBuffTarget > zcs->inBuffSize)
+ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
+ DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
+ (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
+ if (!lastBlock)
+ assert(zcs->inBuffTarget <= zcs->inBuffSize);
+ zcs->inToCompress = zcs->inBuffPos;
+ if (cDst == op) { /* no need to flush */
+ op += cSize;
+ if (zcs->frameEnded) {
+ DEBUGLOG(5, "Frame completed directly in outBuffer");
+ someMoreWork = 0;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ }
+ break;
+ }
+ zcs->outBuffContentSize = cSize;
+ zcs->outBuffFlushedSize = 0;
+ zcs->streamStage = zcss_flush; /* pass-through to flush stage */
+ }
+ /* fall-through */
+ case zcss_flush:
+ DEBUGLOG(5, "flush stage");
+ { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
+ size_t const flushed = ZSTD_limitCopy(op, oend-op,
+ zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
+ DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
+ (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
+ op += flushed;
+ zcs->outBuffFlushedSize += flushed;
+ if (toFlush!=flushed) {
+ /* flush not fully completed, presumably because dst is too small */
+ assert(op==oend);
+ someMoreWork = 0;
+ break;
+ }
+ zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
+ if (zcs->frameEnded) {
+ DEBUGLOG(5, "Frame completed on flush");
+ someMoreWork = 0;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ break;
+ }
+ zcs->streamStage = zcss_load;
+ break;
+ }
+
+ default: /* impossible */
+ assert(0);
+ }
+ }
+
+ input->pos = ip - istart;
+ output->pos = op - ostart;
+ if (zcs->frameEnded) return 0;
+ return ZSTD_nextInputSizeHint(zcs);
+}
+
+static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers >= 1) {
+ assert(cctx->mtctx != NULL);
+ return ZSTDMT_nextInputSizeHint(cctx->mtctx);
+ }
+#endif
+ return ZSTD_nextInputSizeHint(cctx);
+
+}
+
+size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ CHECK_F( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) );
+ return ZSTD_nextInputSizeHint_MTorST(zcs);
+}
+
+
+size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective endOp)
+{
+ DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
+ /* check conditions */
+ if (output->pos > output->size) return ERROR(GENERIC);
+ if (input->pos > input->size) return ERROR(GENERIC);
+ assert(cctx!=NULL);
+
+ /* transparent initialization stage */
+ if (cctx->streamStage == zcss_init) {
+ ZSTD_CCtx_params params = cctx->requestedParams;
+ ZSTD_prefixDict const prefixDict = cctx->prefixDict;
+ memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
+ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
+ DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
+ if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
+ params.cParams = ZSTD_getCParamsFromCCtxParams(
+ &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
+
+
+#ifdef ZSTD_MULTITHREAD
+ if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
+ params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
+ }
+ if (params.nbWorkers > 0) {
+ /* mt context creation */
+ if (cctx->mtctx == NULL) {
+ DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
+ params.nbWorkers);
+ cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem);
+ if (cctx->mtctx == NULL) return ERROR(memory_allocation);
+ }
+ /* mt compression */
+ DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
+ CHECK_F( ZSTDMT_initCStream_internal(
+ cctx->mtctx,
+ prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent,
+ cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
+ cctx->streamStage = zcss_load;
+ cctx->appliedParams.nbWorkers = params.nbWorkers;
+ } else
+#endif
+ { CHECK_F( ZSTD_resetCStream_internal(cctx,
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
+ cctx->cdict,
+ params, cctx->pledgedSrcSizePlusOne-1) );
+ assert(cctx->streamStage == zcss_load);
+ assert(cctx->appliedParams.nbWorkers == 0);
+ } }
+ /* end of transparent initialization stage */
+
+ /* compression stage */
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ if (cctx->cParamsChanged) {
+ ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
+ cctx->cParamsChanged = 0;
+ }
+ { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
+ if ( ZSTD_isError(flushMin)
+ || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
+ ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+ }
+ DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
+ return flushMin;
+ } }
+#endif
+ CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
+ DEBUGLOG(5, "completed ZSTD_compressStream2");
+ return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
+}
+
+size_t ZSTD_compressStream2_simpleArgs (
+ ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos,
+ ZSTD_EndDirective endOp)
+{
+ ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+ ZSTD_inBuffer input = { src, srcSize, *srcPos };
+ /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
+ size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
+ *dstPos = output.pos;
+ *srcPos = input.pos;
+ return cErr;
+}
+
+size_t ZSTD_compress2(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+ { size_t oPos = 0;
+ size_t iPos = 0;
+ size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
+ dst, dstCapacity, &oPos,
+ src, srcSize, &iPos,
+ ZSTD_e_end);
+ if (ZSTD_isError(result)) return result;
+ if (result != 0) { /* compression not completed, due to lack of output space */
+ assert(oPos == dstCapacity);
+ return ERROR(dstSize_tooSmall);
+ }
+ assert(iPos == srcSize); /* all input is expected consumed */
+ return oPos;
+ }
+}
+
+/*====== Finalize ======*/
+
+/*! ZSTD_flushStream() :
+ * @return : amount of data remaining to flush */
+size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+ ZSTD_inBuffer input = { NULL, 0, 0 };
+ return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
+}
+
+
+size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+ ZSTD_inBuffer input = { NULL, 0, 0 };
+ size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
+ CHECK_F( remainingToFlush );
+ if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */
+ /* single thread mode : attempt to calculate remaining to flush more precisely */
+ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
+ size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
+ size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
+ DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
+ return toFlush;
+ }
+}
+
+
+/*-===== Pre-defined compression levels =====-*/
+
+#define ZSTD_MAX_CLEVEL 22
+int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
+int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
+
+static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
+{ /* "default" - guarantees a monotonically increasing memory budget */
+ /* W, C, H, S, L, TL, strat */
+ { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
+ { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */
+ { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */
+ { 21, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */
+ { 21, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */
+ { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */
+ { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */
+ { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */
+ { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
+ { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */
+ { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
+ { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
+ { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
+ { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */
+ { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
+ { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
+ { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */
+ { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */
+ { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */
+ { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */
+ { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */
+ { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */
+ { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */
+},
+{ /* for srcSize <= 256 KB */
+ /* W, C, H, S, L, T, strat */
+ { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */
+ { 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */
+ { 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */
+ { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/
+ { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/
+ { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/
+ { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */
+ { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
+ { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
+ { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
+ { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/
+ { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/
+ { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */
+ { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
+ { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/
+ { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/
+ { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/
+ { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/
+ { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+{ /* for srcSize <= 128 KB */
+ /* W, C, H, S, L, T, strat */
+ { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */
+ { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */
+ { 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */
+ { 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */
+ { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */
+ { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
+ { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */
+ { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
+ { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
+ { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
+ { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */
+ { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */
+ { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/
+ { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
+ { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/
+ { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/
+ { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/
+ { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/
+ { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+{ /* for srcSize <= 16 KB */
+ /* W, C, H, S, L, T, strat */
+ { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */
+ { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */
+ { 14, 14, 15, 2, 4, 1, ZSTD_dfast }, /* level 3 */
+ { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */
+ { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/
+ { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */
+ { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */
+ { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/
+ { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/
+ { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/
+ { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/
+ { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/
+ { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/
+ { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/
+ { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/
+ { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/
+ { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/
+ { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/
+ { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+};
+
+/*! ZSTD_getCParams() :
+* @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
+* Size values are optional, provide 0 if not known or unused */
+ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
+{
+ size_t const addedSize = srcSizeHint ? 0 : 500;
+ U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
+ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
+ int row = compressionLevel;
+ DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel);
+ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
+ if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
+ if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
+ { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
+ if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
+ return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
+ }
+}
+
+/*! ZSTD_getParams() :
+* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
+* All fields of `ZSTD_frameParameters` are set to default (0) */
+ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
+ ZSTD_parameters params;
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
+ DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
+ memset(&params, 0, sizeof(params));
+ params.cParams = cParams;
+ params.fParams.contentSizeFlag = 1;
+ return params;
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_compress_internal.h b/Utilities/cmzstd/lib/compress/zstd_compress_internal.h
new file mode 100644
index 000000000..29bca5985
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_compress_internal.h
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* This header contains definitions
+ * that shall **only** be used by modules within lib/compress.
+ */
+
+#ifndef ZSTD_COMPRESS_H
+#define ZSTD_COMPRESS_H
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include "zstd_internal.h"
+#ifdef ZSTD_MULTITHREAD
+# include "zstdmt_compress.h"
+#endif
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*-*************************************
+* Constants
+***************************************/
+#define kSearchStrength 8
+#define HASH_READ_SIZE 8
+#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index 1 now means "unsorted".
+ It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
+ It's not a big deal though : candidate will just be sorted again.
+ Additionnally, candidate position 1 will be lost.
+ But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy
+ Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
+
+
+/*-*************************************
+* Context memory management
+***************************************/
+typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
+typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
+
+typedef struct ZSTD_prefixDict_s {
+ const void* dict;
+ size_t dictSize;
+ ZSTD_dictContentType_e dictContentType;
+} ZSTD_prefixDict;
+
+typedef struct {
+ U32 CTable[HUF_CTABLE_SIZE_U32(255)];
+ HUF_repeat repeatMode;
+} ZSTD_hufCTables_t;
+
+typedef struct {
+ FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
+ FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
+ FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
+ FSE_repeat offcode_repeatMode;
+ FSE_repeat matchlength_repeatMode;
+ FSE_repeat litlength_repeatMode;
+} ZSTD_fseCTables_t;
+
+typedef struct {
+ ZSTD_hufCTables_t huf;
+ ZSTD_fseCTables_t fse;
+} ZSTD_entropyCTables_t;
+
+typedef struct {
+ U32 off;
+ U32 len;
+} ZSTD_match_t;
+
+typedef struct {
+ int price;
+ U32 off;
+ U32 mlen;
+ U32 litlen;
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_optimal_t;
+
+typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
+
+typedef struct {
+ /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
+ unsigned* litFreq; /* table of literals statistics, of size 256 */
+ unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
+ unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
+ unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
+ ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
+ ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
+
+ U32 litSum; /* nb of literals */
+ U32 litLengthSum; /* nb of litLength codes */
+ U32 matchLengthSum; /* nb of matchLength codes */
+ U32 offCodeSum; /* nb of offset codes */
+ U32 litSumBasePrice; /* to compare to log2(litfreq) */
+ U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
+ U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
+ U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
+ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
+ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
+} optState_t;
+
+typedef struct {
+ ZSTD_entropyCTables_t entropy;
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_compressedBlockState_t;
+
+typedef struct {
+ BYTE const* nextSrc; /* next block here to continue on current prefix */
+ BYTE const* base; /* All regular indexes relative to this position */
+ BYTE const* dictBase; /* extDict indexes relative to this position */
+ U32 dictLimit; /* below that point, need extDict */
+ U32 lowLimit; /* below that point, no more data */
+} ZSTD_window_t;
+
+typedef struct ZSTD_matchState_t ZSTD_matchState_t;
+struct ZSTD_matchState_t {
+ ZSTD_window_t window; /* State for window round buffer management */
+ U32 loadedDictEnd; /* index of end of dictionary */
+ U32 nextToUpdate; /* index from which to continue table update */
+ U32 nextToUpdate3; /* index from which to continue table update */
+ U32 hashLog3; /* dispatch table : larger == faster, more memory */
+ U32* hashTable;
+ U32* hashTable3;
+ U32* chainTable;
+ optState_t opt; /* optimal parser state */
+ const ZSTD_matchState_t * dictMatchState;
+ ZSTD_compressionParameters cParams;
+};
+
+typedef struct {
+ ZSTD_compressedBlockState_t* prevCBlock;
+ ZSTD_compressedBlockState_t* nextCBlock;
+ ZSTD_matchState_t matchState;
+} ZSTD_blockState_t;
+
+typedef struct {
+ U32 offset;
+ U32 checksum;
+} ldmEntry_t;
+
+typedef struct {
+ ZSTD_window_t window; /* State for the window round buffer management */
+ ldmEntry_t* hashTable;
+ BYTE* bucketOffsets; /* Next position in bucket to insert entry */
+ U64 hashPower; /* Used to compute the rolling hash.
+ * Depends on ldmParams.minMatchLength */
+} ldmState_t;
+
+typedef struct {
+ U32 enableLdm; /* 1 if enable long distance matching */
+ U32 hashLog; /* Log size of hashTable */
+ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
+ U32 minMatchLength; /* Minimum match length */
+ U32 hashRateLog; /* Log number of entries to skip */
+ U32 windowLog; /* Window log for the LDM */
+} ldmParams_t;
+
+typedef struct {
+ U32 offset;
+ U32 litLength;
+ U32 matchLength;
+} rawSeq;
+
+typedef struct {
+ rawSeq* seq; /* The start of the sequences */
+ size_t pos; /* The position where reading stopped. <= size. */
+ size_t size; /* The number of sequences. <= capacity. */
+ size_t capacity; /* The capacity starting from `seq` pointer */
+} rawSeqStore_t;
+
+struct ZSTD_CCtx_params_s {
+ ZSTD_format_e format;
+ ZSTD_compressionParameters cParams;
+ ZSTD_frameParameters fParams;
+
+ int compressionLevel;
+ int forceWindow; /* force back-references to respect limit of
+ * 1<<wLog, even for dictionary */
+
+ ZSTD_dictAttachPref_e attachDictPref;
+
+ /* Multithreading: used to pass parameters to mtctx */
+ int nbWorkers;
+ size_t jobSize;
+ int overlapLog;
+ int rsyncable;
+
+ /* Long distance matching parameters */
+ ldmParams_t ldmParams;
+
+ /* Internal use, for createCCtxParams() and freeCCtxParams() only */
+ ZSTD_customMem customMem;
+}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
+
+struct ZSTD_CCtx_s {
+ ZSTD_compressionStage_e stage;
+ int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
+ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+ ZSTD_CCtx_params requestedParams;
+ ZSTD_CCtx_params appliedParams;
+ U32 dictID;
+
+ int workSpaceOversizedDuration;
+ void* workSpace;
+ size_t workSpaceSize;
+ size_t blockSize;
+ unsigned long long pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
+ unsigned long long consumedSrcSize;
+ unsigned long long producedCSize;
+ XXH64_state_t xxhState;
+ ZSTD_customMem customMem;
+ size_t staticSize;
+
+ seqStore_t seqStore; /* sequences storage ptrs */
+ ldmState_t ldmState; /* long distance matching state */
+ rawSeq* ldmSequences; /* Storage for the ldm output sequences */
+ size_t maxNbLdmSequences;
+ rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
+ ZSTD_blockState_t blockState;
+ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
+
+ /* streaming */
+ char* inBuff;
+ size_t inBuffSize;
+ size_t inToCompress;
+ size_t inBuffPos;
+ size_t inBuffTarget;
+ char* outBuff;
+ size_t outBuffSize;
+ size_t outBuffContentSize;
+ size_t outBuffFlushedSize;
+ ZSTD_cStreamStage streamStage;
+ U32 frameEnded;
+
+ /* Dictionary */
+ ZSTD_CDict* cdictLocal;
+ const ZSTD_CDict* cdict;
+ ZSTD_prefixDict prefixDict; /* single-usage dictionary */
+
+ /* Multi-threading */
+#ifdef ZSTD_MULTITHREAD
+ ZSTDMT_CCtx* mtctx;
+#endif
+};
+
+typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
+
+typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
+
+
+typedef size_t (*ZSTD_blockCompressor) (
+ ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
+
+
+MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
+{
+ static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21,
+ 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24 };
+ static const U32 LL_deltaCode = 19;
+ return (litLength > 63) ? ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
+}
+
+/* ZSTD_MLcode() :
+ * note : mlBase = matchLength - MINMATCH;
+ * because it's the format it's stored in seqStore->sequences */
+MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
+{
+ static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+ 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
+ static const U32 ML_deltaCode = 36;
+ return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
+}
+
+/*! ZSTD_storeSeq() :
+ * Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
+ * `offsetCode` : distance to match + 3 (values 1-3 are repCodes).
+ * `mlBase` : matchLength - MINMATCH
+*/
+MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase)
+{
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
+ static const BYTE* g_start = NULL;
+ if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
+ { U32 const pos = (U32)((const BYTE*)literals - g_start);
+ DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
+ pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
+ }
+#endif
+ assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq);
+ /* copy Literals */
+ assert(seqStorePtr->maxNbLit <= 128 KB);
+ assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
+ ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
+ seqStorePtr->lit += litLength;
+
+ /* literal Length */
+ if (litLength>0xFFFF) {
+ assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+ seqStorePtr->longLengthID = 1;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
+ seqStorePtr->sequences[0].litLength = (U16)litLength;
+
+ /* match offset */
+ seqStorePtr->sequences[0].offset = offsetCode + 1;
+
+ /* match Length */
+ if (mlBase>0xFFFF) {
+ assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+ seqStorePtr->longLengthID = 2;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
+ seqStorePtr->sequences[0].matchLength = (U16)mlBase;
+
+ seqStorePtr->sequences++;
+}
+
+
+/*-*************************************
+* Match length counter
+***************************************/
+static unsigned ZSTD_NbCommonBytes (size_t val)
+{
+ if (MEM_isLittleEndian()) {
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ _BitScanForward64( &r, (U64)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 4)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
+ 0, 3, 1, 3, 1, 4, 2, 7,
+ 0, 2, 3, 6, 1, 5, 3, 5,
+ 1, 3, 4, 4, 2, 5, 6, 7,
+ 7, 0, 1, 2, 3, 3, 4, 6,
+ 2, 6, 5, 5, 3, 4, 5, 6,
+ 7, 1, 2, 4, 6, 4, 4, 5,
+ 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r=0;
+ _BitScanForward( &r, (U32)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
+ 3, 2, 2, 1, 3, 2, 0, 1,
+ 3, 3, 1, 2, 2, 2, 2, 0,
+ 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ } else { /* Big Endian CPU */
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 4)
+ return (__builtin_clzll(val) >> 3);
+# else
+ unsigned r;
+ const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
+ if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r = 0;
+ _BitScanReverse( &r, (unsigned long)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } }
+}
+
+
+MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
+{
+ const BYTE* const pStart = pIn;
+ const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
+
+ if (pIn < pInLoopLimit) {
+ { size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+ if (diff) return ZSTD_NbCommonBytes(diff); }
+ pIn+=sizeof(size_t); pMatch+=sizeof(size_t);
+ while (pIn < pInLoopLimit) {
+ size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+ if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
+ pIn += ZSTD_NbCommonBytes(diff);
+ return (size_t)(pIn - pStart);
+ } }
+ if (MEM_64bits() && (pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
+ if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
+ if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+ return (size_t)(pIn - pStart);
+}
+
+/** ZSTD_count_2segments() :
+ * can count match length with `ip` & `match` in 2 different segments.
+ * convention : on reaching mEnd, match count continue starting from iStart
+ */
+MEM_STATIC size_t
+ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
+ const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
+{
+ const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
+ size_t const matchLength = ZSTD_count(ip, match, vEnd);
+ if (match + matchLength != mEnd) return matchLength;
+ DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
+ DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
+ DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
+ DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
+ DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
+ return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
+}
+
+
+/*-*************************************
+ * Hashes
+ ***************************************/
+static const U32 prime3bytes = 506832829U;
+static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
+MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
+
+static const U32 prime4bytes = 2654435761U;
+static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
+static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
+
+static const U64 prime5bytes = 889523592379ULL;
+static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
+static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
+
+static const U64 prime6bytes = 227718039650203ULL;
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+
+static const U64 prime7bytes = 58295818150454627ULL;
+static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
+static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
+
+static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+
+MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
+{
+ switch(mls)
+ {
+ default:
+ case 4: return ZSTD_hash4Ptr(p, hBits);
+ case 5: return ZSTD_hash5Ptr(p, hBits);
+ case 6: return ZSTD_hash6Ptr(p, hBits);
+ case 7: return ZSTD_hash7Ptr(p, hBits);
+ case 8: return ZSTD_hash8Ptr(p, hBits);
+ }
+}
+
+/** ZSTD_ipow() :
+ * Return base^exponent.
+ */
+static U64 ZSTD_ipow(U64 base, U64 exponent)
+{
+ U64 power = 1;
+ while (exponent) {
+ if (exponent & 1) power *= base;
+ exponent >>= 1;
+ base *= base;
+ }
+ return power;
+}
+
+#define ZSTD_ROLL_HASH_CHAR_OFFSET 10
+
+/** ZSTD_rollingHash_append() :
+ * Add the buffer to the hash value.
+ */
+static U64 ZSTD_rollingHash_append(U64 hash, void const* buf, size_t size)
+{
+ BYTE const* istart = (BYTE const*)buf;
+ size_t pos;
+ for (pos = 0; pos < size; ++pos) {
+ hash *= prime8bytes;
+ hash += istart[pos] + ZSTD_ROLL_HASH_CHAR_OFFSET;
+ }
+ return hash;
+}
+
+/** ZSTD_rollingHash_compute() :
+ * Compute the rolling hash value of the buffer.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_compute(void const* buf, size_t size)
+{
+ return ZSTD_rollingHash_append(0, buf, size);
+}
+
+/** ZSTD_rollingHash_primePower() :
+ * Compute the primePower to be passed to ZSTD_rollingHash_rotate() for a hash
+ * over a window of length bytes.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_primePower(U32 length)
+{
+ return ZSTD_ipow(prime8bytes, length - 1);
+}
+
+/** ZSTD_rollingHash_rotate() :
+ * Rotate the rolling hash by one byte.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64 primePower)
+{
+ hash -= (toRemove + ZSTD_ROLL_HASH_CHAR_OFFSET) * primePower;
+ hash *= prime8bytes;
+ hash += toAdd + ZSTD_ROLL_HASH_CHAR_OFFSET;
+ return hash;
+}
+
+/*-*************************************
+* Round buffer management
+***************************************/
+/* Max current allowed */
+#define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
+/* Maximum chunk size before overflow correction needs to be called again */
+#define ZSTD_CHUNKSIZE_MAX \
+ ( ((U32)-1) /* Maximum ending current index */ \
+ - ZSTD_CURRENT_MAX) /* Maximum beginning lowLimit */
+
+/**
+ * ZSTD_window_clear():
+ * Clears the window containing the history by simply setting it to empty.
+ */
+MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
+{
+ size_t const endT = (size_t)(window->nextSrc - window->base);
+ U32 const end = (U32)endT;
+
+ window->lowLimit = end;
+ window->dictLimit = end;
+}
+
+/**
+ * ZSTD_window_hasExtDict():
+ * Returns non-zero if the window has a non-empty extDict.
+ */
+MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
+{
+ return window.lowLimit < window.dictLimit;
+}
+
+/**
+ * ZSTD_matchState_dictMode():
+ * Inspects the provided matchState and figures out what dictMode should be
+ * passed to the compressor.
+ */
+MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
+{
+ return ZSTD_window_hasExtDict(ms->window) ?
+ ZSTD_extDict :
+ ms->dictMatchState != NULL ?
+ ZSTD_dictMatchState :
+ ZSTD_noDict;
+}
+
+/**
+ * ZSTD_window_needOverflowCorrection():
+ * Returns non-zero if the indices are getting too large and need overflow
+ * protection.
+ */
+MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
+ void const* srcEnd)
+{
+ U32 const current = (U32)((BYTE const*)srcEnd - window.base);
+ return current > ZSTD_CURRENT_MAX;
+}
+
+/**
+ * ZSTD_window_correctOverflow():
+ * Reduces the indices to protect from index overflow.
+ * Returns the correction made to the indices, which must be applied to every
+ * stored index.
+ *
+ * The least significant cycleLog bits of the indices must remain the same,
+ * which may be 0. Every index up to maxDist in the past must be valid.
+ * NOTE: (maxDist & cycleMask) must be zero.
+ */
+MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
+ U32 maxDist, void const* src)
+{
+ /* preemptive overflow correction:
+ * 1. correction is large enough:
+ * lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog
+ * 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
+ *
+ * current - newCurrent
+ * > (3<<29 + 1<<windowLog) - (1<<windowLog + 1<<chainLog)
+ * > (3<<29) - (1<<chainLog)
+ * > (3<<29) - (1<<30) (NOTE: chainLog <= 30)
+ * > 1<<29
+ *
+ * 2. (ip+ZSTD_CHUNKSIZE_MAX - cctx->base) doesn't overflow:
+ * After correction, current is less than (1<<chainLog + 1<<windowLog).
+ * In 64-bit mode we are safe, because we have 64-bit ptrdiff_t.
+ * In 32-bit mode we are safe, because (chainLog <= 29), so
+ * ip+ZSTD_CHUNKSIZE_MAX - cctx->base < 1<<32.
+ * 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
+ * windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
+ */
+ U32 const cycleMask = (1U << cycleLog) - 1;
+ U32 const current = (U32)((BYTE const*)src - window->base);
+ U32 const newCurrent = (current & cycleMask) + maxDist;
+ U32 const correction = current - newCurrent;
+ assert((maxDist & cycleMask) == 0);
+ assert(current > newCurrent);
+ /* Loose bound, should be around 1<<29 (see above) */
+ assert(correction > 1<<28);
+
+ window->base += correction;
+ window->dictBase += correction;
+ window->lowLimit -= correction;
+ window->dictLimit -= correction;
+
+ DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
+ window->lowLimit);
+ return correction;
+}
+
+/**
+ * ZSTD_window_enforceMaxDist():
+ * Updates lowLimit so that:
+ * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
+ *
+ * This allows a simple check that index >= lowLimit to see if index is valid.
+ * This must be called before a block compression call, with srcEnd as the block
+ * source end.
+ *
+ * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
+ * This is because dictionaries are allowed to be referenced as long as the last
+ * byte of the dictionary is in the window, but once they are out of range,
+ * they cannot be referenced. If loadedDictEndPtr is NULL, we use
+ * loadedDictEnd == 0.
+ *
+ * In normal dict mode, the dict is between lowLimit and dictLimit. In
+ * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
+ * is below them. forceWindow and dictMatchState are therefore incompatible.
+ */
+MEM_STATIC void
+ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
+ void const* srcEnd,
+ U32 maxDist,
+ U32* loadedDictEndPtr,
+ const ZSTD_matchState_t** dictMatchStatePtr)
+{
+ U32 const blockEndIdx = (U32)((BYTE const*)srcEnd - window->base);
+ U32 loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
+ DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u",
+ (unsigned)blockEndIdx, (unsigned)maxDist);
+ if (blockEndIdx > maxDist + loadedDictEnd) {
+ U32 const newLowLimit = blockEndIdx - maxDist;
+ if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
+ if (window->dictLimit < window->lowLimit) {
+ DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
+ (unsigned)window->dictLimit, (unsigned)window->lowLimit);
+ window->dictLimit = window->lowLimit;
+ }
+ if (loadedDictEndPtr)
+ *loadedDictEndPtr = 0;
+ if (dictMatchStatePtr)
+ *dictMatchStatePtr = NULL;
+ }
+}
+
+/**
+ * ZSTD_window_update():
+ * Updates the window by appending [src, src + srcSize) to the window.
+ * If it is not contiguous, the current prefix becomes the extDict, and we
+ * forget about the extDict. Handles overlap of the prefix and extDict.
+ * Returns non-zero if the segment is contiguous.
+ */
+MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
+ void const* src, size_t srcSize)
+{
+ BYTE const* const ip = (BYTE const*)src;
+ U32 contiguous = 1;
+ DEBUGLOG(5, "ZSTD_window_update");
+ /* Check if blocks follow each other */
+ if (src != window->nextSrc) {
+ /* not contiguous */
+ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
+ DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
+ window->lowLimit = window->dictLimit;
+ assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
+ window->dictLimit = (U32)distanceFromBase;
+ window->dictBase = window->base;
+ window->base = ip - distanceFromBase;
+ // ms->nextToUpdate = window->dictLimit;
+ if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */
+ contiguous = 0;
+ }
+ window->nextSrc = ip + srcSize;
+ /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
+ if ( (ip+srcSize > window->dictBase + window->lowLimit)
+ & (ip < window->dictBase + window->dictLimit)) {
+ ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
+ U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
+ window->lowLimit = lowLimitMax;
+ DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
+ }
+ return contiguous;
+}
+
+
+/* debug functions */
+#if (DEBUGLEVEL>=2)
+
+MEM_STATIC double ZSTD_fWeight(U32 rawStat)
+{
+ U32 const fp_accuracy = 8;
+ U32 const fp_multiplier = (1 << fp_accuracy);
+ U32 const newStat = rawStat + 1;
+ U32 const hb = ZSTD_highbit32(newStat);
+ U32 const BWeight = hb * fp_multiplier;
+ U32 const FWeight = (newStat << fp_accuracy) >> hb;
+ U32 const weight = BWeight + FWeight;
+ assert(hb + fp_accuracy < 31);
+ return (double)weight / fp_multiplier;
+}
+
+/* display a table content,
+ * listing each element, its frequency, and its predicted bit cost */
+MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
+{
+ unsigned u, sum;
+ for (u=0, sum=0; u<=max; u++) sum += table[u];
+ DEBUGLOG(2, "total nb elts: %u", sum);
+ for (u=0; u<=max; u++) {
+ DEBUGLOG(2, "%2u: %5u (%.2f)",
+ u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
+ }
+}
+
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* ==============================================================
+ * Private declarations
+ * These prototypes shall only be called from within lib/compress
+ * ============================================================== */
+
+/* ZSTD_getCParamsFromCCtxParams() :
+ * cParams are built depending on compressionLevel, src size hints,
+ * LDM and manually set compression parameters.
+ */
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
+
+/*! ZSTD_initCStream_internal() :
+ * Private use only. Init streaming operation.
+ * expects params to be valid.
+ * must receive dict, or cdict, or none, but not both.
+ * @return : 0, or an error code */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr);
+
+/*! ZSTD_compressStream_generic() :
+ * Private use only. To be called from zstdmt_compress.c in single-thread mode. */
+size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective const flushMode);
+
+/*! ZSTD_getCParamsFromCDict() :
+ * as the name implies */
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
+
+/* ZSTD_compressBegin_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ unsigned long long pledgedSrcSize);
+
+/* ZSTD_compress_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_CCtx_params params);
+
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ * or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
+
+
+/* ZSTD_referenceExternalSequences() :
+ * Must be called before starting a compression operation.
+ * seqs must parse a prefix of the source.
+ * This cannot be used when long range matching is enabled.
+ * Zstd will use these sequences, and pass the literals to a secondary block
+ * compressor.
+ * @return : An error code on failure.
+ * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
+ * access and data corruption.
+ */
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
+
+
+#endif /* ZSTD_COMPRESS_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_double_fast.c b/Utilities/cmzstd/lib/compress/zstd_double_fast.c
new file mode 100644
index 000000000..47faf6d64
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_double_fast.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_double_fast.h"
+
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashLarge = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32 const mls = cParams->minMatch;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->window.base;
+ const BYTE* ip = base + ms->nextToUpdate;
+ const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ const U32 fastHashFillStep = 3;
+
+ /* Always insert every fastHashFillStep position into the hash tables.
+ * Insert the other positions into the large hash table if their entry
+ * is empty.
+ */
+ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
+ U32 const current = (U32)(ip - base);
+ U32 i;
+ for (i = 0; i < fastHashFillStep; ++i) {
+ size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
+ size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
+ if (i == 0)
+ hashSmall[smHash] = current + i;
+ if (i == 0 || hashLarge[lgHash] == 0)
+ hashLarge[lgHash] = current + i;
+ /* Only load extra positions for ZSTD_dtlm_full */
+ if (dtlm == ZSTD_dtlm_fast)
+ break;
+ }
+ }
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_doubleFast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32* const hashLong = ms->hashTable;
+ const U32 hBitsL = cParams->hashLog;
+ U32* const hashSmall = ms->chainTable;
+ const U32 hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 prefixLowestIndex = ms->window.dictLimit;
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1=rep[0], offset_2=rep[1];
+ U32 offsetSaved = 0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dictCParams =
+ dictMode == ZSTD_dictMatchState ?
+ &dms->cParams : NULL;
+ const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
+ dms->hashTable : NULL;
+ const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
+ dms->chainTable : NULL;
+ const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
+ dms->window.dictLimit : 0;
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
+ dms->window.base : NULL;
+ const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
+ dictBase + dictStartIndex : NULL;
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
+ dms->window.nextSrc : NULL;
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
+ 0;
+ const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ?
+ dictCParams->hashLog : hBitsL;
+ const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ?
+ dictCParams->chainLog : hBitsS;
+ const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
+
+ assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
+
+ /* init */
+ ip += (dictAndPrefixLength == 0);
+ if (dictMode == ZSTD_noDict) {
+ U32 const maxRep = (U32)(ip - prefixLowest);
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+ }
+
+ /* Main Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ size_t mLength;
+ U32 offset;
+ size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
+ size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
+ size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
+ size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
+ U32 const current = (U32)(ip-base);
+ U32 const matchIndexL = hashLong[h2];
+ U32 matchIndexS = hashSmall[h];
+ const BYTE* matchLong = base + matchIndexL;
+ const BYTE* match = base + matchIndexS;
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ hashLong[h2] = hashSmall[h] = current; /* update hash tables */
+
+ /* check dictMatchState repcode */
+ if (dictMode == ZSTD_dictMatchState
+ && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ goto _match_stored;
+ }
+
+ /* check noDict repcode */
+ if ( dictMode == ZSTD_noDict
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+ mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ goto _match_stored;
+ }
+
+ if (matchIndexL > prefixLowestIndex) {
+ /* check prefix long match */
+ if (MEM_read64(matchLong) == MEM_read64(ip)) {
+ mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
+ offset = (U32)(ip-matchLong);
+ while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dictMatchState long match */
+ U32 const dictMatchIndexL = dictHashLong[dictHL];
+ const BYTE* dictMatchL = dictBase + dictMatchIndexL;
+ assert(dictMatchL < dictEnd);
+
+ if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
+ mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
+ offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
+ while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ }
+
+ if (matchIndexS > prefixLowestIndex) {
+ /* check prefix short match */
+ if (MEM_read32(match) == MEM_read32(ip)) {
+ goto _search_next_long;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dictMatchState short match */
+ U32 const dictMatchIndexS = dictHashSmall[dictHS];
+ match = dictBase + dictMatchIndexS;
+ matchIndexS = dictMatchIndexS + dictIndexDelta;
+
+ if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
+ goto _search_next_long;
+ }
+ }
+
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
+ continue;
+
+_search_next_long:
+
+ {
+ size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
+ U32 const matchIndexL3 = hashLong[hl3];
+ const BYTE* matchL3 = base + matchIndexL3;
+ hashLong[hl3] = current + 1;
+
+ /* check prefix long +1 match */
+ if (matchIndexL3 > prefixLowestIndex) {
+ if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
+ mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
+ ip++;
+ offset = (U32)(ip-matchL3);
+ while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dict long +1 match */
+ U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
+ const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
+ assert(dictMatchL3 < dictEnd);
+ if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
+ mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
+ ip++;
+ offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
+ while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ }
+ }
+
+ /* if no long +1 match, explore the short match we found */
+ if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
+ offset = (U32)(current - matchIndexS);
+ while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ } else {
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+ offset = (U32)(ip - match);
+ while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ }
+
+ /* fall-through */
+
+_match_found:
+ offset_2 = offset_1;
+ offset_1 = offset;
+
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+_match_stored:
+ /* match found */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
+ hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
+ hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
+
+ /* check immediate repcode */
+ if (dictMode == ZSTD_dictMatchState) {
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
+ && repIndex2 < prefixLowestIndex ?
+ dictBase - dictIndexDelta + repIndex2 :
+ base + repIndex2;
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (dictMode == ZSTD_noDict) {
+ while ( (ip <= ilimit)
+ && ( (offset_2>0)
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ /* store sequence */
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
+ ip += rLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ } } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const U32 mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
+ }
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const U32 mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
+ }
+}
+
+
+static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls /* template */)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32* const hashLong = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const U32 prefixStartIndex = ms->window.dictLimit;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const U32 dictStartIndex = ms->window.lowLimit;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const dictStart = dictBase + dictStartIndex;
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
+ U32 offset_1=rep[0], offset_2=rep[1];
+
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
+
+ /* Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
+ const U32 matchIndex = hashSmall[hSmall];
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* match = matchBase + matchIndex;
+
+ const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
+ const U32 matchLongIndex = hashLong[hLong];
+ const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* matchLong = matchLongBase + matchLongIndex;
+
+ const U32 current = (U32)(ip-base);
+ const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ size_t mLength;
+ hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
+
+ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
+ & (repIndex > dictStartIndex))
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ } else {
+ if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
+ const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
+ U32 offset;
+ mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
+ offset = current - matchLongIndex;
+ while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+ } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
+ size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ U32 const matchIndex3 = hashLong[h3];
+ const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
+ const BYTE* match3 = match3Base + matchIndex3;
+ U32 offset;
+ hashLong[h3] = current + 1;
+ if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
+ const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
+ mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
+ ip++;
+ offset = current+1 - matchIndex3;
+ while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
+ } else {
+ const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+ offset = current - matchIndex;
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ }
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+ } else {
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
+ continue;
+ } }
+
+ /* found a match : store it */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
+ hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
+ hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
+ & (repIndex2 > dictStartIndex))
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ U32 const mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_double_fast.h b/Utilities/cmzstd/lib/compress/zstd_double_fast.h
new file mode 100644
index 000000000..4fa31acfc
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_double_fast.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_DOUBLE_FAST_H
+#define ZSTD_DOUBLE_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "mem.h" /* U32 */
+#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_DOUBLE_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_fast.c b/Utilities/cmzstd/lib/compress/zstd_fast.c
new file mode 100644
index 000000000..40ba0f73e
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_fast.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_fast.h"
+
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hBits = cParams->hashLog;
+ U32 const mls = cParams->minMatch;
+ const BYTE* const base = ms->window.base;
+ const BYTE* ip = base + ms->nextToUpdate;
+ const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ const U32 fastHashFillStep = 3;
+
+ /* Always insert every fastHashFillStep position into the hash table.
+ * Insert the other positions if their hash entry is empty.
+ */
+ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
+ U32 const current = (U32)(ip - base);
+ size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
+ hashTable[hash0] = current;
+ if (dtlm == ZSTD_dtlm_fast) continue;
+ /* Only load extra positions for ZSTD_dtlm_full */
+ { U32 p;
+ for (p = 1; p < fastHashFillStep; ++p) {
+ size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
+ if (hashTable[hash] == 0) { /* not yet filled */
+ hashTable[hash] = current + p;
+ } } } }
+}
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_fast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls, ZSTD_dictMode_e const dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hlog = cParams->hashLog;
+ /* support stepSize of 0 */
+ U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+ const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 prefixStartIndex = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1=rep[0], offset_2=rep[1];
+ U32 offsetSaved = 0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dictCParams =
+ dictMode == ZSTD_dictMatchState ?
+ &dms->cParams : NULL;
+ const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ?
+ dms->hashTable : NULL;
+ const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
+ dms->window.dictLimit : 0;
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
+ dms->window.base : NULL;
+ const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
+ dictBase + dictStartIndex : NULL;
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
+ dms->window.nextSrc : NULL;
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
+ prefixStartIndex - (U32)(dictEnd - dictBase) :
+ 0;
+ const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart);
+ const U32 dictHLog = dictMode == ZSTD_dictMatchState ?
+ dictCParams->hashLog : hlog;
+
+ assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
+
+ /* otherwise, we would get index underflow when translating a dict index
+ * into a local index */
+ assert(dictMode != ZSTD_dictMatchState
+ || prefixStartIndex >= (U32)(dictEnd - dictBase));
+
+ /* init */
+ ip += (dictAndPrefixLength == 0);
+ if (dictMode == ZSTD_noDict) {
+ U32 const maxRep = (U32)(ip - prefixStart);
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+ }
+
+ /* Main Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ size_t mLength;
+ size_t const h = ZSTD_hashPtr(ip, hlog, mls);
+ U32 const current = (U32)(ip-base);
+ U32 const matchIndex = hashTable[h];
+ const BYTE* match = base + matchIndex;
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+ && repIndex < prefixStartIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ hashTable[h] = current; /* update hash table */
+
+ if ( (dictMode == ZSTD_dictMatchState)
+ && ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ } else if ( dictMode == ZSTD_noDict
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+ mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ } else if ( (matchIndex <= prefixStartIndex) ) {
+ if (dictMode == ZSTD_dictMatchState) {
+ size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
+ U32 const dictMatchIndex = dictHashTable[dictHash];
+ const BYTE* dictMatch = dictBase + dictMatchIndex;
+ if (dictMatchIndex <= dictStartIndex ||
+ MEM_read32(dictMatch) != MEM_read32(ip)) {
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ } else {
+ /* found a dict match */
+ U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
+ mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
+ while (((ip>anchor) & (dictMatch>dictStart))
+ && (ip[-1] == dictMatch[-1])) {
+ ip--; dictMatch--; mLength++;
+ } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ }
+ } else {
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ }
+ } else if (MEM_read32(match) != MEM_read32(ip)) {
+ /* it's not a match, and we're not going to check the dictionary */
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ } else {
+ /* found a regular match */
+ U32 const offset = (U32)(ip-match);
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+ while (((ip>anchor) & (match>prefixStart))
+ && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ }
+
+ /* match found */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ assert(base+current+2 > istart); /* check base overflow */
+ hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */
+ hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+
+ /* check immediate repcode */
+ if (dictMode == ZSTD_dictMatchState) {
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
+ dictBase - dictIndexDelta + repIndex2 :
+ base + repIndex2;
+ if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (dictMode == ZSTD_noDict) {
+ while ( (ip <= ilimit)
+ && ( (offset_2>0)
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ /* store sequence */
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
+ ip += rLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ } } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32 const mls = cParams->minMatch;
+ assert(ms->dictMatchState == NULL);
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
+ case 5 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
+ case 6 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
+ case 7 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
+ }
+}
+
+size_t ZSTD_compressBlock_fast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32 const mls = cParams->minMatch;
+ assert(ms->dictMatchState != NULL);
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
+ case 5 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
+ case 6 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
+ case 7 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
+ }
+}
+
+
+static size_t ZSTD_compressBlock_fast_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize, U32 const mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hlog = cParams->hashLog;
+ /* support stepSize of 0 */
+ U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 dictStartIndex = ms->window.lowLimit;
+ const BYTE* const dictStart = dictBase + dictStartIndex;
+ const U32 prefixStartIndex = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ U32 offset_1=rep[0], offset_2=rep[1];
+
+ /* Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ const size_t h = ZSTD_hashPtr(ip, hlog, mls);
+ const U32 matchIndex = hashTable[h];
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* match = matchBase + matchIndex;
+ const U32 current = (U32)(ip-base);
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ size_t mLength;
+ hashTable[h] = current; /* update hash table */
+ assert(offset_1 <= current +1); /* check repIndex */
+
+ if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+ } else {
+ if ( (matchIndex < dictStartIndex) ||
+ (MEM_read32(match) != MEM_read32(ip)) ) {
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ }
+ { const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+ U32 offset;
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ offset = current - matchIndex;
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ } }
+
+ /* found a match : store it */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
+ hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32 const mls = cParams->minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_fast.h b/Utilities/cmzstd/lib/compress/zstd_fast.h
new file mode 100644
index 000000000..b74a88c57
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_fast.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_FAST_H
+#define ZSTD_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "mem.h" /* U32 */
+#include "zstd_compress_internal.h"
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_lazy.c b/Utilities/cmzstd/lib/compress/zstd_lazy.c
new file mode 100644
index 000000000..53f998a43
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_lazy.c
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_lazy.h"
+
+
+/*-*************************************
+* Binary Tree search
+***************************************/
+
+static void
+ZSTD_updateDUBT(ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iend,
+ U32 mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+
+ const BYTE* const base = ms->window.base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ if (idx != target)
+ DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
+ idx, target, ms->window.dictLimit);
+ assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
+ (void)iend;
+
+ assert(idx >= ms->window.dictLimit); /* condition for valid base+idx */
+ for ( ; idx < target ; idx++) {
+ size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
+ U32 const matchIndex = hashTable[h];
+
+ U32* const nextCandidatePtr = bt + 2*(idx&btMask);
+ U32* const sortMarkPtr = nextCandidatePtr + 1;
+
+ DEBUGLOG(8, "ZSTD_updateDUBT: insert %u", idx);
+ hashTable[h] = idx; /* Update Hash Table */
+ *nextCandidatePtr = matchIndex; /* update BT like a chain */
+ *sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
+ }
+ ms->nextToUpdate = target;
+}
+
+
+/** ZSTD_insertDUBT1() :
+ * sort one already inserted but unsorted position
+ * assumption : current >= btlow == (current - btmask)
+ * doesn't fail */
+static void
+ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
+ U32 current, const BYTE* inputEnd,
+ U32 nbCompares, U32 btLow,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
+ const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* match;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = smallerPtr + 1;
+ U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */
+ U32 dummy32; /* to be nullified at the end */
+ U32 const windowLow = ms->window.lowLimit;
+
+ DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
+ current, dictLimit, windowLow);
+ assert(current >= btLow);
+ assert(ip < iend); /* condition for ZSTD_count */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(matchIndex < current);
+ /* note : all candidates are now supposed sorted,
+ * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK
+ * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */
+
+ if ( (dictMode != ZSTD_extDict)
+ || (matchIndex+matchLength >= dictLimit) /* both in current segment*/
+ || (current < dictLimit) /* both in extDict */) {
+ const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
+ || (matchIndex+matchLength >= dictLimit)) ?
+ base : dictBase;
+ assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
+ || (current < dictLimit) );
+ match = mBase + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* preparation for next read of match[matchLength] */
+ }
+
+ DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
+ current, matchIndex, (U32)matchLength);
+
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+ }
+
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u",
+ matchIndex, btLow, nextPtr[1]);
+ smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
+ matchIndex, btLow, nextPtr[0]);
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+}
+
+
+static size_t
+ZSTD_DUBT_findBetterDictMatch (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ size_t* offsetPtr,
+ size_t bestLength,
+ U32 nbCompares,
+ U32 const mls,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_matchState_t * const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dmsCParams = &dms->cParams;
+ const U32 * const dictHashTable = dms->hashTable;
+ U32 const hashLog = dmsCParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 dictMatchIndex = dictHashTable[h];
+
+ const BYTE* const base = ms->window.base;
+ const BYTE* const prefixStart = base + ms->window.dictLimit;
+ U32 const current = (U32)(ip-base);
+ const BYTE* const dictBase = dms->window.base;
+ const BYTE* const dictEnd = dms->window.nextSrc;
+ U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
+ U32 const dictLowLimit = dms->window.lowLimit;
+ U32 const dictIndexDelta = ms->window.lowLimit - dictHighLimit;
+
+ U32* const dictBt = dms->chainTable;
+ U32 const btLog = dmsCParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask;
+
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+
+ (void)dictMode;
+ assert(dictMode == ZSTD_dictMatchState);
+
+ while (nbCompares-- && (dictMatchIndex > dictLowLimit)) {
+ U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match = dictBase + dictMatchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (dictMatchIndex+matchLength >= dictHighLimit)
+ match = base + dictMatchIndex + dictIndexDelta; /* to prepare for next usage of match[matchLength] */
+
+ if (matchLength > bestLength) {
+ U32 matchIndex = dictMatchIndex + dictIndexDelta;
+ if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
+ DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
+ current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+ }
+ if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
+ commonLengthLarger = matchLength;
+ dictMatchIndex = nextPtr[0];
+ }
+ }
+
+ if (bestLength >= MINMATCH) {
+ U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+ DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+ }
+ return bestLength;
+
+}
+
+
+static size_t
+ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ size_t* offsetPtr,
+ U32 const mls,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 matchIndex = hashTable[h];
+
+ const BYTE* const base = ms->window.base;
+ U32 const current = (U32)(ip-base);
+ U32 const windowLow = ms->window.lowLimit;
+
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 const btLow = (btMask >= current) ? 0 : current - btMask;
+ U32 const unsortLimit = MAX(btLow, windowLow);
+
+ U32* nextCandidate = bt + 2*(matchIndex&btMask);
+ U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ U32 nbCompares = 1U << cParams->searchLog;
+ U32 nbCandidates = nbCompares;
+ U32 previousCandidate = 0;
+
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
+ assert(ip <= iend-8); /* required for h calculation */
+
+ /* reach end of unsorted candidates list */
+ while ( (matchIndex > unsortLimit)
+ && (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
+ && (nbCandidates > 1) ) {
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch: candidate %u is unsorted",
+ matchIndex);
+ *unsortedMark = previousCandidate; /* the unsortedMark becomes a reversed chain, to move up back to original position */
+ previousCandidate = matchIndex;
+ matchIndex = *nextCandidate;
+ nextCandidate = bt + 2*(matchIndex&btMask);
+ unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ nbCandidates --;
+ }
+
+ /* nullify last candidate if it's still unsorted
+ * simplification, detrimental to compression ratio, beneficial for speed */
+ if ( (matchIndex > unsortLimit)
+ && (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u",
+ matchIndex);
+ *nextCandidate = *unsortedMark = 0;
+ }
+
+ /* batch sort stacked candidates */
+ matchIndex = previousCandidate;
+ while (matchIndex) { /* will end on matchIndex == 0 */
+ U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
+ U32 const nextCandidateIdx = *nextCandidateIdxPtr;
+ ZSTD_insertDUBT1(ms, matchIndex, iend,
+ nbCandidates, unsortLimit, dictMode);
+ matchIndex = nextCandidateIdx;
+ nbCandidates++;
+ }
+
+ /* find longest match */
+ { size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
+ U32 matchEndIdx = current + 8 + 1;
+ U32 dummy32; /* to be nullified at the end */
+ size_t bestLength = 0;
+
+ matchIndex = hashTable[h];
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match;
+
+ if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) {
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ if (dictMode == ZSTD_dictMatchState) {
+ nbCompares = 0; /* in addition to avoiding checking any
+ * further in this loop, make sure we
+ * skip checking in the dictionary. */
+ }
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+
+ if (dictMode == ZSTD_dictMatchState && nbCompares) {
+ bestLength = ZSTD_DUBT_findBetterDictMatch(
+ ms, ip, iend,
+ offsetPtr, bestLength, nbCompares,
+ mls, dictMode);
+ }
+
+ assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ if (bestLength >= MINMATCH) {
+ U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+ }
+ return bestLength;
+ }
+}
+
+
+/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ size_t* offsetPtr,
+ const U32 mls /* template */,
+ const ZSTD_dictMode_e dictMode)
+{
+ DEBUGLOG(7, "ZSTD_BtFindBestMatch");
+ if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateDUBT(ms, ip, iLimit, mls);
+ return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode);
+}
+
+
+static size_t
+ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+ }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+ }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+ }
+}
+
+
+
+/* *********************************
+* Hash Chain
+***********************************/
+#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & (mask)]
+
+/* Update chains up to ip (excluded)
+ Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndex_internal(
+ ZSTD_matchState_t* ms,
+ const ZSTD_compressionParameters* const cParams,
+ const BYTE* ip, U32 const mls)
+{
+ U32* const hashTable = ms->hashTable;
+ const U32 hashLog = cParams->hashLog;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainMask = (1 << cParams->chainLog) - 1;
+ const BYTE* const base = ms->window.base;
+ const U32 target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ while(idx < target) { /* catch up */
+ size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
+ NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
+ hashTable[h] = idx;
+ idx++;
+ }
+
+ ms->nextToUpdate = target;
+ return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
+}
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
+}
+
+
+/* inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_HcFindBestMatch_generic (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ size_t* offsetPtr,
+ const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainSize = (1 << cParams->chainLog);
+ const U32 chainMask = chainSize-1;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const U32 lowLimit = ms->window.lowLimit;
+ const U32 current = (U32)(ip-base);
+ const U32 minChain = current > chainSize ? current - chainSize : 0;
+ U32 nbAttempts = 1U << cParams->searchLog;
+ size_t ml=4-1;
+
+ /* HC4 match finder */
+ U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
+
+ for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
+ size_t currentMl=0;
+ if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+ const BYTE* const match = base + matchIndex;
+ assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */
+ if (match[ml] == ip[ml]) /* potentially better */
+ currentMl = ZSTD_count(ip, match, iLimit);
+ } else {
+ const BYTE* const match = dictBase + matchIndex;
+ assert(match+4 <= dictEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
+ }
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+
+ if (matchIndex <= minChain) break;
+ matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
+ }
+
+ if (dictMode == ZSTD_dictMatchState) {
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const U32* const dmsChainTable = dms->chainTable;
+ const U32 dmsChainSize = (1 << dms->cParams.chainLog);
+ const U32 dmsChainMask = dmsChainSize - 1;
+ const U32 dmsLowestIndex = dms->window.dictLimit;
+ const BYTE* const dmsBase = dms->window.base;
+ const BYTE* const dmsEnd = dms->window.nextSrc;
+ const U32 dmsSize = (U32)(dmsEnd - dmsBase);
+ const U32 dmsIndexDelta = dictLimit - dmsSize;
+ const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0;
+
+ matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)];
+
+ for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
+ size_t currentMl=0;
+ const BYTE* const match = dmsBase + matchIndex;
+ assert(match+4 <= dmsEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+
+ if (matchIndex <= dmsMinChain) break;
+ matchIndex = dmsChainTable[matchIndex & dmsChainMask];
+ }
+ }
+
+ return ml;
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+ }
+}
+
+
+static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+ }
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+ }
+}
+
+
+/* *******************************
+* Common parser - lazy strategy
+*********************************/
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_lazy_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const U32 searchMethod, const U32 depth,
+ ZSTD_dictMode_e const dictMode)
+{
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const U32 prefixLowestIndex = ms->window.dictLimit;
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
+
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+ searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
+ (searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
+ (searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS);
+ U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ?
+ dms->window.dictLimit : 0;
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
+ dms->window.base : NULL;
+ const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ?
+ dictBase + dictLowestIndex : NULL;
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
+ dms->window.nextSrc : NULL;
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
+ 0;
+ const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest);
+
+ /* init */
+ ip += (dictAndPrefixLength == 0);
+ ms->nextToUpdate3 = ms->nextToUpdate;
+ if (dictMode == ZSTD_noDict) {
+ U32 const maxRep = (U32)(ip - prefixLowest);
+ if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+ }
+
+ /* Match Loop */
+ while (ip < ilimit) {
+ size_t matchLength=0;
+ size_t offset=0;
+ const BYTE* start=ip+1;
+
+ /* check repCode */
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ if (depth==0) goto _storeSequence;
+ }
+ }
+ if ( dictMode == ZSTD_noDict
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+ matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ if (depth==0) goto _storeSequence;
+ }
+
+ /* first search (depth 0) */
+ { size_t offsetFound = 999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+ if (ml2 > matchLength)
+ matchLength = ml2, start = ip, offset=offsetFound;
+ }
+
+ if (matchLength < 4) {
+ ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
+ continue;
+ }
+
+ /* let's try to find a better solution */
+ if (depth>=1)
+ while (ip<ilimit) {
+ ip ++;
+ if ( (dictMode == ZSTD_noDict)
+ && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+ size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+ int const gain2 = (int)(mlRep * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) - offset_1;
+ const BYTE* repMatch = repIndex < prefixLowestIndex ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ int const gain2 = (int)(mlRep * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ }
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue; /* search a better one */
+ } }
+
+ /* let's find an even better one */
+ if ((depth==2) && (ip<ilimit)) {
+ ip ++;
+ if ( (dictMode == ZSTD_noDict)
+ && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+ size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+ int const gain2 = (int)(mlRep * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) - offset_1;
+ const BYTE* repMatch = repIndex < prefixLowestIndex ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ int const gain2 = (int)(mlRep * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ }
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ } } }
+ break; /* nothing found : store previous solution */
+ }
+
+ /* NOTE:
+ * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
+ * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
+ * overflows the pointer, which is undefined behavior.
+ */
+ /* catch up */
+ if (offset) {
+ if (dictMode == ZSTD_noDict) {
+ while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest))
+ && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
+ { start--; matchLength++; }
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+ const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
+ const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
+ while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
+ }
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ }
+ /* store sequence */
+_storeSequence:
+ { size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+ anchor = ip = start + matchLength;
+ }
+
+ /* check immediate repcode */
+ if (dictMode == ZSTD_dictMatchState) {
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex = current2 - offset_2;
+ const BYTE* repMatch = dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex ?
+ dictBase - dictIndexDelta + repIndex :
+ base + repIndex;
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (dictMode == ZSTD_noDict) {
+ while ( ((ip <= ilimit) & (offset_2>0))
+ && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
+ /* store sequence */
+ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ } } }
+
+ /* Save reps for next block */
+ rep[0] = offset_1 ? offset_1 : savedOffset;
+ rep[1] = offset_2 ? offset_2 : savedOffset;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_dictMatchState);
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_lazy_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const U32 searchMethod, const U32 depth)
+{
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const U32 dictLimit = ms->window.dictLimit;
+ const U32 lowestIndex = ms->window.lowLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const dictStart = dictBase + lowestIndex;
+
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+ searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
+
+ U32 offset_1 = rep[0], offset_2 = rep[1];
+
+ /* init */
+ ms->nextToUpdate3 = ms->nextToUpdate;
+ ip += (ip == prefixStart);
+
+ /* Match Loop */
+ while (ip < ilimit) {
+ size_t matchLength=0;
+ size_t offset=0;
+ const BYTE* start=ip+1;
+ U32 current = (U32)(ip-base);
+
+ /* check repCode */
+ { const U32 repIndex = (U32)(current+1 - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ if (depth==0) goto _storeSequence;
+ } }
+
+ /* first search (depth 0) */
+ { size_t offsetFound = 999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+ if (ml2 > matchLength)
+ matchLength = ml2, start = ip, offset=offsetFound;
+ }
+
+ if (matchLength < 4) {
+ ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
+ continue;
+ }
+
+ /* let's try to find a better solution */
+ if (depth>=1)
+ while (ip<ilimit) {
+ ip ++;
+ current++;
+ /* check repCode */
+ if (offset) {
+ const U32 repIndex = (U32)(current - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ int const gain2 = (int)(repLength * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((repLength >= 4) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ } }
+
+ /* search match, depth 1 */
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue; /* search a better one */
+ } }
+
+ /* let's find an even better one */
+ if ((depth==2) && (ip<ilimit)) {
+ ip ++;
+ current++;
+ /* check repCode */
+ if (offset) {
+ const U32 repIndex = (U32)(current - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ int const gain2 = (int)(repLength * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((repLength >= 4) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ } }
+
+ /* search match, depth 2 */
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ } } }
+ break; /* nothing found : store previous solution */
+ }
+
+ /* catch up */
+ if (offset) {
+ U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+ const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
+ const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
+ while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ }
+
+ /* store sequence */
+_storeSequence:
+ { size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+ anchor = ip = start + matchLength;
+ }
+
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ const U32 repIndex = (U32)((ip-base) - offset_2);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ }
+ break;
+ } }
+
+ /* Save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 0);
+}
+
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 1);
+}
+
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 2);
+}
+
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 1, 2);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_lazy.h b/Utilities/cmzstd/lib/compress/zstd_lazy.h
new file mode 100644
index 000000000..ef85a6df9
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_lazy.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LAZY_H
+#define ZSTD_LAZY_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
+
+void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */
+
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_LAZY_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_ldm.c b/Utilities/cmzstd/lib/compress/zstd_ldm.c
new file mode 100644
index 000000000..58eb2ffe4
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_ldm.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include "zstd_ldm.h"
+
+#include "debug.h"
+#include "zstd_fast.h" /* ZSTD_fillHashTable() */
+#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
+
+#define LDM_BUCKET_SIZE_LOG 3
+#define LDM_MIN_MATCH_LENGTH 64
+#define LDM_HASH_RLOG 7
+#define LDM_HASH_CHAR_OFFSET 10
+
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+ ZSTD_compressionParameters const* cParams)
+{
+ params->windowLog = cParams->windowLog;
+ ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
+ DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
+ if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
+ if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
+ if (cParams->strategy >= ZSTD_btopt) {
+ /* Get out of the way of the optimal parser */
+ U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
+ assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
+ assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
+ params->minMatchLength = minMatch;
+ }
+ if (params->hashLog == 0) {
+ params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
+ assert(params->hashLog <= ZSTD_HASHLOG_MAX);
+ }
+ if (params->hashRateLog == 0) {
+ params->hashRateLog = params->windowLog < params->hashLog
+ ? 0
+ : params->windowLog - params->hashLog;
+ }
+ params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
+}
+
+size_t ZSTD_ldm_getTableSize(ldmParams_t params)
+{
+ size_t const ldmHSize = ((size_t)1) << params.hashLog;
+ size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
+ size_t const ldmBucketSize =
+ ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
+ size_t const totalSize = ldmBucketSize + ldmHSize * sizeof(ldmEntry_t);
+ return params.enableLdm ? totalSize : 0;
+}
+
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
+{
+ return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
+}
+
+/** ZSTD_ldm_getSmallHash() :
+ * numBits should be <= 32
+ * If numBits==0, returns 0.
+ * @return : the most significant numBits of value. */
+static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
+{
+ assert(numBits <= 32);
+ return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
+}
+
+/** ZSTD_ldm_getChecksum() :
+ * numBitsToDiscard should be <= 32
+ * @return : the next most significant 32 bits after numBitsToDiscard */
+static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
+{
+ assert(numBitsToDiscard <= 32);
+ return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
+}
+
+/** ZSTD_ldm_getTag() ;
+ * Given the hash, returns the most significant numTagBits bits
+ * after (32 + hbits) bits.
+ *
+ * If there are not enough bits remaining, return the last
+ * numTagBits bits. */
+static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
+{
+ assert(numTagBits < 32 && hbits <= 32);
+ if (32 - hbits < numTagBits) {
+ return hash & (((U32)1 << numTagBits) - 1);
+ } else {
+ return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
+ }
+}
+
+/** ZSTD_ldm_getBucket() :
+ * Returns a pointer to the start of the bucket associated with hash. */
+static ldmEntry_t* ZSTD_ldm_getBucket(
+ ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
+{
+ return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
+}
+
+/** ZSTD_ldm_insertEntry() :
+ * Insert the entry with corresponding hash into the hash table */
+static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
+ size_t const hash, const ldmEntry_t entry,
+ ldmParams_t const ldmParams)
+{
+ BYTE* const bucketOffsets = ldmState->bucketOffsets;
+ *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
+ bucketOffsets[hash]++;
+ bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
+}
+
+/** ZSTD_ldm_makeEntryAndInsertByTag() :
+ *
+ * Gets the small hash, checksum, and tag from the rollingHash.
+ *
+ * If the tag matches (1 << ldmParams.hashRateLog)-1, then
+ * creates an ldmEntry from the offset, and inserts it into the hash table.
+ *
+ * hBits is the length of the small hash, which is the most significant hBits
+ * of rollingHash. The checksum is the next 32 most significant bits, followed
+ * by ldmParams.hashRateLog bits that make up the tag. */
+static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
+ U64 const rollingHash,
+ U32 const hBits,
+ U32 const offset,
+ ldmParams_t const ldmParams)
+{
+ U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
+ U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
+ if (tag == tagMask) {
+ U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
+ U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+ ldmEntry_t entry;
+ entry.offset = offset;
+ entry.checksum = checksum;
+ ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
+ }
+}
+
+/** ZSTD_ldm_countBackwardsMatch() :
+ * Returns the number of bytes that match backwards before pIn and pMatch.
+ *
+ * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
+static size_t ZSTD_ldm_countBackwardsMatch(
+ const BYTE* pIn, const BYTE* pAnchor,
+ const BYTE* pMatch, const BYTE* pBase)
+{
+ size_t matchLength = 0;
+ while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
+ pIn--;
+ pMatch--;
+ matchLength++;
+ }
+ return matchLength;
+}
+
+/** ZSTD_ldm_fillFastTables() :
+ *
+ * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
+ * This is similar to ZSTD_loadDictionaryContent.
+ *
+ * The tables for the other strategies are filled within their
+ * block compressors. */
+static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
+ void const* end)
+{
+ const BYTE* const iend = (const BYTE*)end;
+
+ switch(ms->cParams.strategy)
+ {
+ case ZSTD_fast:
+ ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
+ break;
+
+ case ZSTD_dfast:
+ ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
+ break;
+
+ case ZSTD_greedy:
+ case ZSTD_lazy:
+ case ZSTD_lazy2:
+ case ZSTD_btlazy2:
+ case ZSTD_btopt:
+ case ZSTD_btultra:
+ case ZSTD_btultra2:
+ break;
+ default:
+ assert(0); /* not possible : not a valid strategy id */
+ }
+
+ return 0;
+}
+
+/** ZSTD_ldm_fillLdmHashTable() :
+ *
+ * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
+ * lastHash is the rolling hash that corresponds to lastHashed.
+ *
+ * Returns the rolling hash corresponding to position iend-1. */
+static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
+ U64 lastHash, const BYTE* lastHashed,
+ const BYTE* iend, const BYTE* base,
+ U32 hBits, ldmParams_t const ldmParams)
+{
+ U64 rollingHash = lastHash;
+ const BYTE* cur = lastHashed + 1;
+
+ while (cur < iend) {
+ rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
+ cur[ldmParams.minMatchLength-1],
+ state->hashPower);
+ ZSTD_ldm_makeEntryAndInsertByTag(state,
+ rollingHash, hBits,
+ (U32)(cur - base), ldmParams);
+ ++cur;
+ }
+ return rollingHash;
+}
+
+
+/** ZSTD_ldm_limitTableUpdate() :
+ *
+ * Sets cctx->nextToUpdate to a position corresponding closer to anchor
+ * if it is far way
+ * (after a long match, only update tables a limited amount). */
+static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
+{
+ U32 const current = (U32)(anchor - ms->window.base);
+ if (current > ms->nextToUpdate + 1024) {
+ ms->nextToUpdate =
+ current - MIN(512, current - ms->nextToUpdate - 1024);
+ }
+}
+
+static size_t ZSTD_ldm_generateSequences_internal(
+ ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
+ ldmParams_t const* params, void const* src, size_t srcSize)
+{
+ /* LDM parameters */
+ int const extDict = ZSTD_window_hasExtDict(ldmState->window);
+ U32 const minMatchLength = params->minMatchLength;
+ U64 const hashPower = ldmState->hashPower;
+ U32 const hBits = params->hashLog - params->bucketSizeLog;
+ U32 const ldmBucketSize = 1U << params->bucketSizeLog;
+ U32 const hashRateLog = params->hashRateLog;
+ U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
+ /* Prefix and extDict parameters */
+ U32 const dictLimit = ldmState->window.dictLimit;
+ U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
+ BYTE const* const base = ldmState->window.base;
+ BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
+ BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
+ BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
+ BYTE const* const lowPrefixPtr = base + dictLimit;
+ /* Input bounds */
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
+ /* Input positions */
+ BYTE const* anchor = istart;
+ BYTE const* ip = istart;
+ /* Rolling hash */
+ BYTE const* lastHashed = NULL;
+ U64 rollingHash = 0;
+
+ while (ip <= ilimit) {
+ size_t mLength;
+ U32 const current = (U32)(ip - base);
+ size_t forwardMatchLength = 0, backwardMatchLength = 0;
+ ldmEntry_t* bestEntry = NULL;
+ if (ip != istart) {
+ rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
+ lastHashed[minMatchLength],
+ hashPower);
+ } else {
+ rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
+ }
+ lastHashed = ip;
+
+ /* Do not insert and do not look for a match */
+ if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
+ ip++;
+ continue;
+ }
+
+ /* Get the best entry and compute the match lengths */
+ {
+ ldmEntry_t* const bucket =
+ ZSTD_ldm_getBucket(ldmState,
+ ZSTD_ldm_getSmallHash(rollingHash, hBits),
+ *params);
+ ldmEntry_t* cur;
+ size_t bestMatchLength = 0;
+ U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+
+ for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
+ size_t curForwardMatchLength, curBackwardMatchLength,
+ curTotalMatchLength;
+ if (cur->checksum != checksum || cur->offset <= lowestIndex) {
+ continue;
+ }
+ if (extDict) {
+ BYTE const* const curMatchBase =
+ cur->offset < dictLimit ? dictBase : base;
+ BYTE const* const pMatch = curMatchBase + cur->offset;
+ BYTE const* const matchEnd =
+ cur->offset < dictLimit ? dictEnd : iend;
+ BYTE const* const lowMatchPtr =
+ cur->offset < dictLimit ? dictStart : lowPrefixPtr;
+
+ curForwardMatchLength = ZSTD_count_2segments(
+ ip, pMatch, iend,
+ matchEnd, lowPrefixPtr);
+ if (curForwardMatchLength < minMatchLength) {
+ continue;
+ }
+ curBackwardMatchLength =
+ ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+ lowMatchPtr);
+ curTotalMatchLength = curForwardMatchLength +
+ curBackwardMatchLength;
+ } else { /* !extDict */
+ BYTE const* const pMatch = base + cur->offset;
+ curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
+ if (curForwardMatchLength < minMatchLength) {
+ continue;
+ }
+ curBackwardMatchLength =
+ ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+ lowPrefixPtr);
+ curTotalMatchLength = curForwardMatchLength +
+ curBackwardMatchLength;
+ }
+
+ if (curTotalMatchLength > bestMatchLength) {
+ bestMatchLength = curTotalMatchLength;
+ forwardMatchLength = curForwardMatchLength;
+ backwardMatchLength = curBackwardMatchLength;
+ bestEntry = cur;
+ }
+ }
+ }
+
+ /* No match found -- continue searching */
+ if (bestEntry == NULL) {
+ ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
+ hBits, current,
+ *params);
+ ip++;
+ continue;
+ }
+
+ /* Match found */
+ mLength = forwardMatchLength + backwardMatchLength;
+ ip -= backwardMatchLength;
+
+ {
+ /* Store the sequence:
+ * ip = current - backwardMatchLength
+ * The match is at (bestEntry->offset - backwardMatchLength)
+ */
+ U32 const matchIndex = bestEntry->offset;
+ U32 const offset = current - matchIndex;
+ rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
+
+ /* Out of sequence storage */
+ if (rawSeqStore->size == rawSeqStore->capacity)
+ return ERROR(dstSize_tooSmall);
+ seq->litLength = (U32)(ip - anchor);
+ seq->matchLength = (U32)mLength;
+ seq->offset = offset;
+ rawSeqStore->size++;
+ }
+
+ /* Insert the current entry into the hash table */
+ ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
+ (U32)(lastHashed - base),
+ *params);
+
+ assert(ip + backwardMatchLength == lastHashed);
+
+ /* Fill the hash table from lastHashed+1 to ip+mLength*/
+ /* Heuristic: don't need to fill the entire table at end of block */
+ if (ip + mLength <= ilimit) {
+ rollingHash = ZSTD_ldm_fillLdmHashTable(
+ ldmState, rollingHash, lastHashed,
+ ip + mLength, base, hBits, *params);
+ lastHashed = ip + mLength - 1;
+ }
+ ip += mLength;
+ anchor = ip;
+ }
+ return iend - anchor;
+}
+
+/*! ZSTD_ldm_reduceTable() :
+ * reduce table indexes by `reducerValue` */
+static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
+ U32 const reducerValue)
+{
+ U32 u;
+ for (u = 0; u < size; u++) {
+ if (table[u].offset < reducerValue) table[u].offset = 0;
+ else table[u].offset -= reducerValue;
+ }
+}
+
+size_t ZSTD_ldm_generateSequences(
+ ldmState_t* ldmState, rawSeqStore_t* sequences,
+ ldmParams_t const* params, void const* src, size_t srcSize)
+{
+ U32 const maxDist = 1U << params->windowLog;
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ size_t const kMaxChunkSize = 1 << 20;
+ size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
+ size_t chunk;
+ size_t leftoverSize = 0;
+
+ assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
+ /* Check that ZSTD_window_update() has been called for this chunk prior
+ * to passing it to this function.
+ */
+ assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
+ /* The input could be very large (in zstdmt), so it must be broken up into
+ * chunks to enforce the maximmum distance and handle overflow correction.
+ */
+ assert(sequences->pos <= sequences->size);
+ assert(sequences->size <= sequences->capacity);
+ for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
+ BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
+ size_t const remaining = (size_t)(iend - chunkStart);
+ BYTE const *const chunkEnd =
+ (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
+ size_t const chunkSize = chunkEnd - chunkStart;
+ size_t newLeftoverSize;
+ size_t const prevSize = sequences->size;
+
+ assert(chunkStart < iend);
+ /* 1. Perform overflow correction if necessary. */
+ if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
+ U32 const ldmHSize = 1U << params->hashLog;
+ U32 const correction = ZSTD_window_correctOverflow(
+ &ldmState->window, /* cycleLog */ 0, maxDist, src);
+ ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
+ }
+ /* 2. We enforce the maximum offset allowed.
+ *
+ * kMaxChunkSize should be small enough that we don't lose too much of
+ * the window through early invalidation.
+ * TODO: * Test the chunk size.
+ * * Try invalidation after the sequence generation and test the
+ * the offset against maxDist directly.
+ */
+ ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL);
+ /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
+ newLeftoverSize = ZSTD_ldm_generateSequences_internal(
+ ldmState, sequences, params, chunkStart, chunkSize);
+ if (ZSTD_isError(newLeftoverSize))
+ return newLeftoverSize;
+ /* 4. We add the leftover literals from previous iterations to the first
+ * newly generated sequence, or add the `newLeftoverSize` if none are
+ * generated.
+ */
+ /* Prepend the leftover literals from the last call */
+ if (prevSize < sequences->size) {
+ sequences->seq[prevSize].litLength += (U32)leftoverSize;
+ leftoverSize = newLeftoverSize;
+ } else {
+ assert(newLeftoverSize == chunkSize);
+ leftoverSize += chunkSize;
+ }
+ }
+ return 0;
+}
+
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
+ while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
+ rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
+ if (srcSize <= seq->litLength) {
+ /* Skip past srcSize literals */
+ seq->litLength -= (U32)srcSize;
+ return;
+ }
+ srcSize -= seq->litLength;
+ seq->litLength = 0;
+ if (srcSize < seq->matchLength) {
+ /* Skip past the first srcSize of the match */
+ seq->matchLength -= (U32)srcSize;
+ if (seq->matchLength < minMatch) {
+ /* The match is too short, omit it */
+ if (rawSeqStore->pos + 1 < rawSeqStore->size) {
+ seq[1].litLength += seq[0].matchLength;
+ }
+ rawSeqStore->pos++;
+ }
+ return;
+ }
+ srcSize -= seq->matchLength;
+ seq->matchLength = 0;
+ rawSeqStore->pos++;
+ }
+}
+
+/**
+ * If the sequence length is longer than remaining then the sequence is split
+ * between this block and the next.
+ *
+ * Returns the current sequence to handle, or if the rest of the block should
+ * be literals, it returns a sequence with offset == 0.
+ */
+static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
+ U32 const remaining, U32 const minMatch)
+{
+ rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
+ assert(sequence.offset > 0);
+ /* Likely: No partial sequence */
+ if (remaining >= sequence.litLength + sequence.matchLength) {
+ rawSeqStore->pos++;
+ return sequence;
+ }
+ /* Cut the sequence short (offset == 0 ==> rest is literals). */
+ if (remaining <= sequence.litLength) {
+ sequence.offset = 0;
+ } else if (remaining < sequence.litLength + sequence.matchLength) {
+ sequence.matchLength = remaining - sequence.litLength;
+ if (sequence.matchLength < minMatch) {
+ sequence.offset = 0;
+ }
+ }
+ /* Skip past `remaining` bytes for the future sequences. */
+ ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
+ return sequence;
+}
+
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ unsigned const minMatch = cParams->minMatch;
+ ZSTD_blockCompressor const blockCompressor =
+ ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
+ /* Input bounds */
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ /* Input positions */
+ BYTE const* ip = istart;
+
+ DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
+ assert(rawSeqStore->pos <= rawSeqStore->size);
+ assert(rawSeqStore->size <= rawSeqStore->capacity);
+ /* Loop through each sequence and apply the block compressor to the lits */
+ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
+ /* maybeSplitSequence updates rawSeqStore->pos */
+ rawSeq const sequence = maybeSplitSequence(rawSeqStore,
+ (U32)(iend - ip), minMatch);
+ int i;
+ /* End signal */
+ if (sequence.offset == 0)
+ break;
+
+ assert(sequence.offset <= (1U << cParams->windowLog));
+ assert(ip + sequence.litLength + sequence.matchLength <= iend);
+
+ /* Fill tables for block compressor */
+ ZSTD_ldm_limitTableUpdate(ms, ip);
+ ZSTD_ldm_fillFastTables(ms, ip);
+ /* Run the block compressor */
+ DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength);
+ {
+ size_t const newLitLength =
+ blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
+ ip += sequence.litLength;
+ /* Update the repcodes */
+ for (i = ZSTD_REP_NUM - 1; i > 0; i--)
+ rep[i] = rep[i-1];
+ rep[0] = sequence.offset;
+ /* Store the sequence */
+ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength,
+ sequence.offset + ZSTD_REP_MOVE,
+ sequence.matchLength - MINMATCH);
+ ip += sequence.matchLength;
+ }
+ }
+ /* Fill the tables for the block compressor */
+ ZSTD_ldm_limitTableUpdate(ms, ip);
+ ZSTD_ldm_fillFastTables(ms, ip);
+ /* Compress the last literals */
+ return blockCompressor(ms, seqStore, rep, ip, iend - ip);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_ldm.h b/Utilities/cmzstd/lib/compress/zstd_ldm.h
new file mode 100644
index 000000000..a47846128
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_ldm.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#ifndef ZSTD_LDM_H
+#define ZSTD_LDM_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h" /* ldmParams_t, U32 */
+#include "zstd.h" /* ZSTD_CCtx, size_t */
+
+/*-*************************************
+* Long distance matching
+***************************************/
+
+#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
+
+/**
+ * ZSTD_ldm_generateSequences():
+ *
+ * Generates the sequences using the long distance match finder.
+ * Generates long range matching sequences in `sequences`, which parse a prefix
+ * of the source. `sequences` must be large enough to store every sequence,
+ * which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
+ * @returns 0 or an error code.
+ *
+ * NOTE: The user must have called ZSTD_window_update() for all of the input
+ * they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
+ * NOTE: This function returns an error if it runs out of space to store
+ * sequences.
+ */
+size_t ZSTD_ldm_generateSequences(
+ ldmState_t* ldms, rawSeqStore_t* sequences,
+ ldmParams_t const* params, void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_blockCompress():
+ *
+ * Compresses a block using the predefined sequences, along with a secondary
+ * block compressor. The literals section of every sequence is passed to the
+ * secondary block compressor, and those sequences are interspersed with the
+ * predefined sequences. Returns the length of the last literals.
+ * Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
+ * `rawSeqStore.seq` may also be updated to split the last sequence between two
+ * blocks.
+ * @return The length of the last literals.
+ *
+ * NOTE: The source must be at most the maximum block size, but the predefined
+ * sequences can be any size, and may be longer than the block. In the case that
+ * they are longer than the block, the last sequences may need to be split into
+ * two. We handle that case correctly, and update `rawSeqStore` appropriately.
+ * NOTE: This function does not return any errors.
+ */
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_skipSequences():
+ *
+ * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
+ * Avoids emitting matches less than `minMatch` bytes.
+ * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ */
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
+ U32 const minMatch);
+
+
+/** ZSTD_ldm_getTableSize() :
+ * Estimate the space needed for long distance matching tables or 0 if LDM is
+ * disabled.
+ */
+size_t ZSTD_ldm_getTableSize(ldmParams_t params);
+
+/** ZSTD_ldm_getSeqSpace() :
+ * Return an upper bound on the number of sequences that can be produced by
+ * the long distance matcher, or 0 if LDM is disabled.
+ */
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
+
+/** ZSTD_ldm_adjustParameters() :
+ * If the params->hashRateLog is not set, set it to its default value based on
+ * windowLog and params->hashLog.
+ *
+ * Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
+ * params->hashLog if it is not).
+ *
+ * Ensures that the minMatchLength >= targetLength during optimal parsing.
+ */
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+ ZSTD_compressionParameters const* cParams);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_opt.c b/Utilities/cmzstd/lib/compress/zstd_opt.c
new file mode 100644
index 000000000..44de6e97f
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_opt.c
@@ -0,0 +1,1217 @@
+/*
+ * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "hist.h"
+#include "zstd_opt.h"
+
+
+#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
+#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */
+#define ZSTD_MAX_PRICE (1<<30)
+
+#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
+
+
+/*-*************************************
+* Price functions for optimal parser
+***************************************/
+
+#if 0 /* approximation at bit level */
+# define BITCOST_ACCURACY 0
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat))
+#elif 0 /* fractional bit accuracy */
+# define BITCOST_ACCURACY 8
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
+#else /* opt==approx, ultra==accurate */
+# define BITCOST_ACCURACY 8
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
+#endif
+
+MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
+{
+ return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
+}
+
+MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
+{
+ U32 const stat = rawStat + 1;
+ U32 const hb = ZSTD_highbit32(stat);
+ U32 const BWeight = hb * BITCOST_MULTIPLIER;
+ U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
+ U32 const weight = BWeight + FWeight;
+ assert(hb + BITCOST_ACCURACY < 31);
+ return weight;
+}
+
+#if (DEBUGLEVEL>=2)
+/* debugging function,
+ * @return price in bytes as fractional value
+ * for debug messages only */
+MEM_STATIC double ZSTD_fCost(U32 price)
+{
+ return (double)price / (BITCOST_MULTIPLIER*8);
+}
+#endif
+
+static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
+{
+ optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
+ optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
+ optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
+ optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
+}
+
+
+/* ZSTD_downscaleStat() :
+ * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus)
+ * return the resulting sum of elements */
+static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus)
+{
+ U32 s, sum=0;
+ DEBUGLOG(5, "ZSTD_downscaleStat (nbElts=%u)", (unsigned)lastEltIndex+1);
+ assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
+ for (s=0; s<lastEltIndex+1; s++) {
+ table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
+ sum += table[s];
+ }
+ return sum;
+}
+
+/* ZSTD_rescaleFreqs() :
+ * if first block (detected by optPtr->litLengthSum == 0) : init statistics
+ * take hints from dictionary if there is one
+ * or init from zero, using src for literals stats, or flat 1 for match symbols
+ * otherwise downscale existing stats, to be used as seed for next block.
+ */
+static void
+ZSTD_rescaleFreqs(optState_t* const optPtr,
+ const BYTE* const src, size_t const srcSize,
+ int const optLevel)
+{
+ DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
+ optPtr->priceType = zop_dynamic;
+
+ if (optPtr->litLengthSum == 0) { /* first block : init */
+ if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */
+ DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef");
+ optPtr->priceType = zop_predef;
+ }
+
+ assert(optPtr->symbolCosts != NULL);
+ if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
+ /* huffman table presumed generated by dictionary */
+ optPtr->priceType = zop_dynamic;
+
+ assert(optPtr->litFreq != NULL);
+ optPtr->litSum = 0;
+ { unsigned lit;
+ for (lit=0; lit<=MaxLit; lit++) {
+ U32 const scaleLog = 11; /* scale to 2K */
+ U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
+ assert(bitCost <= scaleLog);
+ optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->litSum += optPtr->litFreq[lit];
+ } }
+
+ { unsigned ll;
+ FSE_CState_t llstate;
+ FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
+ optPtr->litLengthSum = 0;
+ for (ll=0; ll<=MaxLL; ll++) {
+ U32 const scaleLog = 10; /* scale to 1K */
+ U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
+ assert(bitCost < scaleLog);
+ optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->litLengthSum += optPtr->litLengthFreq[ll];
+ } }
+
+ { unsigned ml;
+ FSE_CState_t mlstate;
+ FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
+ optPtr->matchLengthSum = 0;
+ for (ml=0; ml<=MaxML; ml++) {
+ U32 const scaleLog = 10;
+ U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
+ assert(bitCost < scaleLog);
+ optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
+ } }
+
+ { unsigned of;
+ FSE_CState_t ofstate;
+ FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
+ optPtr->offCodeSum = 0;
+ for (of=0; of<=MaxOff; of++) {
+ U32 const scaleLog = 10;
+ U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
+ assert(bitCost < scaleLog);
+ optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->offCodeSum += optPtr->offCodeFreq[of];
+ } }
+
+ } else { /* not a dictionary */
+
+ assert(optPtr->litFreq != NULL);
+ { unsigned lit = MaxLit;
+ HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
+ }
+ optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+
+ { unsigned ll;
+ for (ll=0; ll<=MaxLL; ll++)
+ optPtr->litLengthFreq[ll] = 1;
+ }
+ optPtr->litLengthSum = MaxLL+1;
+
+ { unsigned ml;
+ for (ml=0; ml<=MaxML; ml++)
+ optPtr->matchLengthFreq[ml] = 1;
+ }
+ optPtr->matchLengthSum = MaxML+1;
+
+ { unsigned of;
+ for (of=0; of<=MaxOff; of++)
+ optPtr->offCodeFreq[of] = 1;
+ }
+ optPtr->offCodeSum = MaxOff+1;
+
+ }
+
+ } else { /* new block : re-use previous statistics, scaled down */
+
+ optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+ optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+ optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+ optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+ }
+
+ ZSTD_setBasePrices(optPtr, optLevel);
+}
+
+/* ZSTD_rawLiteralsCost() :
+ * price of literals (only) in specified segment (which length can be 0).
+ * does not include price of literalLength symbol */
+static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
+ const optState_t* const optPtr,
+ int optLevel)
+{
+ if (litLength == 0) return 0;
+ if (optPtr->priceType == zop_predef)
+ return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */
+
+ /* dynamic statistics */
+ { U32 price = litLength * optPtr->litSumBasePrice;
+ U32 u;
+ for (u=0; u < litLength; u++) {
+ assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */
+ price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
+ }
+ return price;
+ }
+}
+
+/* ZSTD_litLengthPrice() :
+ * cost of literalLength symbol */
+static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
+{
+ if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
+
+ /* dynamic statistics */
+ { U32 const llCode = ZSTD_LLcode(litLength);
+ return (LL_bits[llCode] * BITCOST_MULTIPLIER)
+ + optPtr->litLengthSumBasePrice
+ - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
+ }
+}
+
+/* ZSTD_litLengthContribution() :
+ * @return ( cost(litlength) - cost(0) )
+ * this value can then be added to rawLiteralsCost()
+ * to provide a cost which is directly comparable to a match ending at same position */
+static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel)
+{
+ if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel);
+
+ /* dynamic statistics */
+ { U32 const llCode = ZSTD_LLcode(litLength);
+ int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER)
+ + WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */
+ - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
+#if 1
+ return contribution;
+#else
+ return MAX(0, contribution); /* sometimes better, sometimes not ... */
+#endif
+ }
+}
+
+/* ZSTD_literalsContribution() :
+ * creates a fake cost for the literals part of a sequence
+ * which can be compared to the ending cost of a match
+ * should a new match start at this position */
+static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
+ const optState_t* const optPtr,
+ int optLevel)
+{
+ int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel)
+ + ZSTD_litLengthContribution(litLength, optPtr, optLevel);
+ return contribution;
+}
+
+/* ZSTD_getMatchPrice() :
+ * Provides the cost of the match part (offset + matchLength) of a sequence
+ * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
+ * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
+FORCE_INLINE_TEMPLATE U32
+ZSTD_getMatchPrice(U32 const offset,
+ U32 const matchLength,
+ const optState_t* const optPtr,
+ int const optLevel)
+{
+ U32 price;
+ U32 const offCode = ZSTD_highbit32(offset+1);
+ U32 const mlBase = matchLength - MINMATCH;
+ assert(matchLength >= MINMATCH);
+
+ if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
+ return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
+
+ /* dynamic statistics */
+ price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
+ if ((optLevel<2) /*static*/ && offCode >= 20)
+ price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
+
+ /* match Length */
+ { U32 const mlCode = ZSTD_MLcode(mlBase);
+ price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
+ }
+
+ price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
+
+ DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
+ return price;
+}
+
+/* ZSTD_updateStats() :
+ * assumption : literals + litLengtn <= iend */
+static void ZSTD_updateStats(optState_t* const optPtr,
+ U32 litLength, const BYTE* literals,
+ U32 offsetCode, U32 matchLength)
+{
+ /* literals */
+ { U32 u;
+ for (u=0; u < litLength; u++)
+ optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
+ optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
+ }
+
+ /* literal Length */
+ { U32 const llCode = ZSTD_LLcode(litLength);
+ optPtr->litLengthFreq[llCode]++;
+ optPtr->litLengthSum++;
+ }
+
+ /* match offset code (0-2=>repCode; 3+=>offset+2) */
+ { U32 const offCode = ZSTD_highbit32(offsetCode+1);
+ assert(offCode <= MaxOff);
+ optPtr->offCodeFreq[offCode]++;
+ optPtr->offCodeSum++;
+ }
+
+ /* match Length */
+ { U32 const mlBase = matchLength - MINMATCH;
+ U32 const mlCode = ZSTD_MLcode(mlBase);
+ optPtr->matchLengthFreq[mlCode]++;
+ optPtr->matchLengthSum++;
+ }
+}
+
+
+/* ZSTD_readMINMATCH() :
+ * function safe only for comparisons
+ * assumption : memPtr must be at least 4 bytes before end of buffer */
+MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
+{
+ switch (length)
+ {
+ default :
+ case 4 : return MEM_read32(memPtr);
+ case 3 : if (MEM_isLittleEndian())
+ return MEM_read32(memPtr)<<8;
+ else
+ return MEM_read32(memPtr)>>8;
+ }
+}
+
+
+/* Update hashTable3 up to ip (excluded)
+ Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
+{
+ U32* const hashTable3 = ms->hashTable3;
+ U32 const hashLog3 = ms->hashLog3;
+ const BYTE* const base = ms->window.base;
+ U32 idx = ms->nextToUpdate3;
+ U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
+ size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
+ assert(hashLog3 > 0);
+
+ while(idx < target) {
+ hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
+ idx++;
+ }
+
+ return hashTable3[hash3];
+}
+
+
+/*-*************************************
+* Binary Tree search
+***************************************/
+/** ZSTD_insertBt1() : add one or multiple positions to tree.
+ * ip : assumed <= iend-8 .
+ * @return : nb of positions added */
+static U32 ZSTD_insertBt1(
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ U32 const mls, const int extDict)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 matchIndex = hashTable[h];
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* match;
+ const U32 current = (U32)(ip-base);
+ const U32 btLow = btMask >= current ? 0 : current - btMask;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = smallerPtr + 1;
+ U32 dummy32; /* to be nullified at the end */
+ U32 const windowLow = ms->window.lowLimit;
+ U32 matchEndIdx = current+8+1;
+ size_t bestLength = 8;
+ U32 nbCompares = 1U << cParams->searchLog;
+#ifdef ZSTD_C_PREDICT
+ U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
+ U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
+ predictedSmall += (predictedSmall>0);
+ predictedLarge += (predictedLarge>0);
+#endif /* ZSTD_C_PREDICT */
+
+ DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+
+ assert(ip <= iend-8); /* required for h calculation */
+ hashTable[h] = current; /* Update Hash Table */
+
+ assert(windowLow > 0);
+ while (nbCompares-- && (matchIndex >= windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(matchIndex < current);
+
+#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
+ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
+ if (matchIndex == predictedSmall) {
+ /* no need to check length, result known */
+ *smallerPtr = matchIndex;
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ predictedSmall = predictPtr[1] + (predictPtr[1]>0);
+ continue;
+ }
+ if (matchIndex == predictedLarge) {
+ *largerPtr = matchIndex;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ predictedLarge = predictPtr[0] + (predictPtr[0]>0);
+ continue;
+ }
+#endif
+
+ if (!extDict || (matchIndex+matchLength >= dictLimit)) {
+ assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ bestLength = matchLength;
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ }
+
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+ }
+
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+ if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
+ assert(matchEndIdx > current + 8);
+ return matchEndIdx - (current + 8);
+}
+
+FORCE_INLINE_TEMPLATE
+void ZSTD_updateTree_internal(
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+ const BYTE* const base = ms->window.base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+ DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
+ idx, target, dictMode);
+
+ while(idx < target)
+ idx += ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict);
+ ms->nextToUpdate = target;
+}
+
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
+ ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
+}
+
+FORCE_INLINE_TEMPLATE
+U32 ZSTD_insertBtAndGetAllMatches (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode,
+ U32 rep[ZSTD_REP_NUM],
+ U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
+ ZSTD_match_t* matches,
+ const U32 lengthToBeat,
+ U32 const mls /* template */)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ const BYTE* const base = ms->window.base;
+ U32 const current = (U32)(ip-base);
+ U32 const hashLog = cParams->hashLog;
+ U32 const minMatch = (mls==3) ? 3 : 4;
+ U32* const hashTable = ms->hashTable;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 matchIndex = hashTable[h];
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask= (1U << btLog) - 1;
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const dictBase = ms->window.dictBase;
+ U32 const dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ U32 const btLow = btMask >= current ? 0 : current - btMask;
+ U32 const windowLow = ms->window.lowLimit;
+ U32 const matchLow = windowLow ? windowLow : 1;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
+ U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
+ U32 dummy32; /* to be nullified at the end */
+ U32 mnum = 0;
+ U32 nbCompares = 1U << cParams->searchLog;
+
+ const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
+ const ZSTD_compressionParameters* const dmsCParams =
+ dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
+ const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
+ const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
+ U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
+ U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
+ U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
+ U32 const dmsHashLog = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
+ U32 const dmsBtLog = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
+ U32 const dmsBtMask = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
+ U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
+
+ size_t bestLength = lengthToBeat-1;
+ DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
+
+ /* check repCode */
+ assert(ll0 <= 1); /* necessarily 1 or 0 */
+ { U32 const lastR = ZSTD_REP_NUM + ll0;
+ U32 repCode;
+ for (repCode = ll0; repCode < lastR; repCode++) {
+ U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+ U32 const repIndex = current - repOffset;
+ U32 repLen = 0;
+ assert(current >= dictLimit);
+ if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */
+ if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
+ repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
+ }
+ } else { /* repIndex < dictLimit || repIndex >= current */
+ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
+ dmsBase + repIndex - dmsIndexDelta :
+ dictBase + repIndex;
+ assert(current >= windowLow);
+ if ( dictMode == ZSTD_extDict
+ && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
+ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
+ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+ repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
+ }
+ if (dictMode == ZSTD_dictMatchState
+ && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */
+ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
+ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+ repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
+ } }
+ /* save longer solution */
+ if (repLen > bestLength) {
+ DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
+ repCode, ll0, repOffset, repLen);
+ bestLength = repLen;
+ matches[mnum].off = repCode - ll0;
+ matches[mnum].len = (U32)repLen;
+ mnum++;
+ if ( (repLen > sufficient_len)
+ | (ip+repLen == iLimit) ) { /* best possible */
+ return mnum;
+ } } } }
+
+ /* HC3 match finder */
+ if ((mls == 3) /*static*/ && (bestLength < mls)) {
+ U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
+ if ((matchIndex3 >= matchLow)
+ & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
+ size_t mlen;
+ if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
+ const BYTE* const match = base + matchIndex3;
+ mlen = ZSTD_count(ip, match, iLimit);
+ } else {
+ const BYTE* const match = dictBase + matchIndex3;
+ mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
+ }
+
+ /* save best solution */
+ if (mlen >= mls /* == 3 > bestLength */) {
+ DEBUGLOG(8, "found small match with hlog3, of length %u",
+ (U32)mlen);
+ bestLength = mlen;
+ assert(current > matchIndex3);
+ assert(mnum==0); /* no prior solution */
+ matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
+ matches[0].len = (U32)mlen;
+ mnum = 1;
+ if ( (mlen > sufficient_len) |
+ (ip+mlen == iLimit) ) { /* best possible length */
+ ms->nextToUpdate = current+1; /* skip insertion */
+ return 1;
+ }
+ }
+ }
+ /* no dictMatchState lookup: dicts don't have a populated HC3 table */
+ }
+
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex >= matchLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match;
+ assert(current > matchIndex);
+
+ if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
+ assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* prepare for match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
+ (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+ assert(matchEndIdx > matchIndex);
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ bestLength = matchLength;
+ matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+ matches[mnum].len = (U32)matchLength;
+ mnum++;
+ if ( (matchLength > ZSTD_OPT_NUM)
+ | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+ if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
+ break; /* drop, to preserve bt consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ /* match smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new candidate => larger than match, which was smaller than current */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous, closer to current */
+ } else {
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+
+ if (dictMode == ZSTD_dictMatchState && nbCompares) {
+ size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
+ U32 dictMatchIndex = dms->hashTable[dmsH];
+ const U32* const dmsBt = dms->chainTable;
+ commonLengthSmaller = commonLengthLarger = 0;
+ while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
+ const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match = dmsBase + dictMatchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
+ if (dictMatchIndex+matchLength >= dmsHighLimit)
+ match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */
+
+ if (matchLength > bestLength) {
+ matchIndex = dictMatchIndex + dmsIndexDelta;
+ DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
+ (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ bestLength = matchLength;
+ matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+ matches[mnum].len = (U32)matchLength;
+ mnum++;
+ if ( (matchLength > ZSTD_OPT_NUM)
+ | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */
+ if (match[matchLength] < ip[matchLength]) {
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ commonLengthLarger = matchLength;
+ dictMatchIndex = nextPtr[0];
+ }
+ }
+ }
+
+ assert(matchEndIdx > current+8);
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ return mnum;
+}
+
+
+FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode,
+ U32 rep[ZSTD_REP_NUM], U32 const ll0,
+ ZSTD_match_t* matches, U32 const lengthToBeat)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32 const matchLengthSearch = cParams->minMatch;
+ DEBUGLOG(8, "ZSTD_BtGetAllMatches");
+ if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode);
+ switch(matchLengthSearch)
+ {
+ case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3);
+ default :
+ case 4 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4);
+ case 5 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5);
+ case 7 :
+ case 6 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6);
+ }
+}
+
+
+/*-*******************************
+* Optimal parser
+*********************************/
+typedef struct repcodes_s {
+ U32 rep[3];
+} repcodes_t;
+
+static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
+{
+ repcodes_t newReps;
+ if (offset >= ZSTD_REP_NUM) { /* full offset */
+ newReps.rep[2] = rep[1];
+ newReps.rep[1] = rep[0];
+ newReps.rep[0] = offset - ZSTD_REP_MOVE;
+ } else { /* repcode */
+ U32 const repCode = offset + ll0;
+ if (repCode > 0) { /* note : if repCode==0, no change */
+ U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+ newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
+ newReps.rep[1] = rep[0];
+ newReps.rep[0] = currentOffset;
+ } else { /* repCode == 0 */
+ memcpy(&newReps, rep, sizeof(newReps));
+ }
+ }
+ return newReps;
+}
+
+
+static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
+{
+ return sol.litlen + sol.mlen;
+}
+
+#if 0 /* debug */
+
+static void
+listStats(const U32* table, int lastEltID)
+{
+ int const nbElts = lastEltID + 1;
+ int enb;
+ for (enb=0; enb < nbElts; enb++) {
+ (void)table;
+ //RAWLOG(2, "%3i:%3i, ", enb, table[enb]);
+ RAWLOG(2, "%4i,", table[enb]);
+ }
+ RAWLOG(2, " \n");
+}
+
+#endif
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
+ seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const int optLevel,
+ const ZSTD_dictMode_e dictMode)
+{
+ optState_t* const optStatePtr = &ms->opt;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const prefixStart = base + ms->window.dictLimit;
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
+
+ ZSTD_optimal_t* const opt = optStatePtr->priceTable;
+ ZSTD_match_t* const matches = optStatePtr->matchTable;
+ ZSTD_optimal_t lastSequence;
+
+ /* init */
+ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
+ (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
+ assert(optLevel <= 2);
+ ms->nextToUpdate3 = ms->nextToUpdate;
+ ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
+ ip += (ip==prefixStart);
+
+ /* Match Loop */
+ while (ip < ilimit) {
+ U32 cur, last_pos = 0;
+
+ /* find first match */
+ { U32 const litlen = (U32)(ip - anchor);
+ U32 const ll0 = !litlen;
+ U32 const nbMatches = ZSTD_BtGetAllMatches(ms, ip, iend, dictMode, rep, ll0, matches, minMatch);
+ if (!nbMatches) { ip++; continue; }
+
+ /* initialize opt[0] */
+ { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
+ opt[0].mlen = 0; /* means is_a_literal */
+ opt[0].litlen = litlen;
+ opt[0].price = ZSTD_literalsContribution(anchor, litlen, optStatePtr, optLevel);
+
+ /* large match -> immediate encoding */
+ { U32 const maxML = matches[nbMatches-1].len;
+ U32 const maxOffset = matches[nbMatches-1].off;
+ DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new serie",
+ nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
+
+ if (maxML > sufficient_len) {
+ lastSequence.litlen = litlen;
+ lastSequence.mlen = maxML;
+ lastSequence.off = maxOffset;
+ DEBUGLOG(6, "large match (%u>%u), immediate encoding",
+ maxML, sufficient_len);
+ cur = 0;
+ last_pos = ZSTD_totalLen(lastSequence);
+ goto _shortestPath;
+ } }
+
+ /* set prices for first matches starting position == 0 */
+ { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+ U32 pos;
+ U32 matchNb;
+ for (pos = 1; pos < minMatch; pos++) {
+ opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
+ }
+ for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+ U32 const offset = matches[matchNb].off;
+ U32 const end = matches[matchNb].len;
+ repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
+ for ( ; pos <= end ; pos++ ) {
+ U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
+ U32 const sequencePrice = literalsPrice + matchPrice;
+ DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
+ pos, ZSTD_fCost(sequencePrice));
+ opt[pos].mlen = pos;
+ opt[pos].off = offset;
+ opt[pos].litlen = litlen;
+ opt[pos].price = sequencePrice;
+ ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
+ memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
+ } }
+ last_pos = pos-1;
+ }
+ }
+
+ /* check further positions */
+ for (cur = 1; cur <= last_pos; cur++) {
+ const BYTE* const inr = ip + cur;
+ assert(cur < ZSTD_OPT_NUM);
+ DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
+
+ /* Fix current position with one literal if cheaper */
+ { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
+ int const price = opt[cur-1].price
+ + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
+ + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
+ - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
+ assert(price < 1000000000); /* overflow check */
+ if (price <= opt[cur].price) {
+ DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
+ inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
+ opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
+ opt[cur].mlen = 0;
+ opt[cur].off = 0;
+ opt[cur].litlen = litlen;
+ opt[cur].price = price;
+ memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
+ } else {
+ DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
+ inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
+ opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
+ }
+ }
+
+ /* last match must start at a minimum distance of 8 from oend */
+ if (inr > ilimit) continue;
+
+ if (cur == last_pos) break;
+
+ if ( (optLevel==0) /*static_test*/
+ && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
+ DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
+ continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
+ }
+
+ { U32 const ll0 = (opt[cur].mlen != 0);
+ U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
+ U32 const previousPrice = opt[cur].price;
+ U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+ U32 const nbMatches = ZSTD_BtGetAllMatches(ms, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch);
+ U32 matchNb;
+ if (!nbMatches) {
+ DEBUGLOG(7, "rPos:%u : no match found", cur);
+ continue;
+ }
+
+ { U32 const maxML = matches[nbMatches-1].len;
+ DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
+ inr-istart, cur, nbMatches, maxML);
+
+ if ( (maxML > sufficient_len)
+ || (cur + maxML >= ZSTD_OPT_NUM) ) {
+ lastSequence.mlen = maxML;
+ lastSequence.off = matches[nbMatches-1].off;
+ lastSequence.litlen = litlen;
+ cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
+ last_pos = cur + ZSTD_totalLen(lastSequence);
+ if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
+ goto _shortestPath;
+ } }
+
+ /* set prices using matches found at position == cur */
+ for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+ U32 const offset = matches[matchNb].off;
+ repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0);
+ U32 const lastML = matches[matchNb].len;
+ U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
+ U32 mlen;
+
+ DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
+ matchNb, matches[matchNb].off, lastML, litlen);
+
+ for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
+ U32 const pos = cur + mlen;
+ int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
+
+ if ((pos > last_pos) || (price < opt[pos].price)) {
+ DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
+ pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+ while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
+ opt[pos].mlen = mlen;
+ opt[pos].off = offset;
+ opt[pos].litlen = litlen;
+ opt[pos].price = price;
+ ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
+ memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
+ } else {
+ DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
+ pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+ if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
+ }
+ } } }
+ } /* for (cur = 1; cur <= last_pos; cur++) */
+
+ lastSequence = opt[last_pos];
+ cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
+ assert(cur < ZSTD_OPT_NUM); /* control overflow*/
+
+_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
+ assert(opt[0].mlen == 0);
+
+ { U32 const storeEnd = cur + 1;
+ U32 storeStart = storeEnd;
+ U32 seqPos = cur;
+
+ DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
+ last_pos, cur); (void)last_pos;
+ assert(storeEnd < ZSTD_OPT_NUM);
+ DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+ storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
+ opt[storeEnd] = lastSequence;
+ while (seqPos > 0) {
+ U32 const backDist = ZSTD_totalLen(opt[seqPos]);
+ storeStart--;
+ DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+ seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
+ opt[storeStart] = opt[seqPos];
+ seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
+ }
+
+ /* save sequences */
+ DEBUGLOG(6, "sending selected sequences into seqStore")
+ { U32 storePos;
+ for (storePos=storeStart; storePos <= storeEnd; storePos++) {
+ U32 const llen = opt[storePos].litlen;
+ U32 const mlen = opt[storePos].mlen;
+ U32 const offCode = opt[storePos].off;
+ U32 const advance = llen + mlen;
+ DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
+ anchor - istart, (unsigned)llen, (unsigned)mlen);
+
+ if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */
+ assert(storePos == storeEnd); /* must be last sequence */
+ ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */
+ continue; /* will finish */
+ }
+
+ /* repcodes update : like ZSTD_updateRep(), but update in place */
+ if (offCode >= ZSTD_REP_NUM) { /* full offset */
+ rep[2] = rep[1];
+ rep[1] = rep[0];
+ rep[0] = offCode - ZSTD_REP_MOVE;
+ } else { /* repcode */
+ U32 const repCode = offCode + (llen==0);
+ if (repCode) { /* note : if repCode==0, no change */
+ U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+ if (repCode >= 2) rep[2] = rep[1];
+ rep[1] = rep[0];
+ rep[0] = currentOffset;
+ } }
+
+ assert(anchor + llen <= iend);
+ ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
+ ZSTD_storeSeq(seqStore, llen, anchor, offCode, mlen-MINMATCH);
+ anchor += advance;
+ ip = anchor;
+ } }
+ ZSTD_setBasePrices(optStatePtr, optLevel);
+ }
+
+ } /* while (ip < ilimit) */
+
+ /* Return the last literals size */
+ return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressBlock_btopt");
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
+}
+
+
+/* used in 2-pass strategy */
+static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
+{
+ U32 s, sum=0;
+ assert(ZSTD_FREQ_DIV+bonus >= 0);
+ for (s=0; s<lastEltIndex+1; s++) {
+ table[s] <<= ZSTD_FREQ_DIV+bonus;
+ table[s]--;
+ sum += table[s];
+ }
+ return sum;
+}
+
+/* used in 2-pass strategy */
+MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
+{
+ optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
+ optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+ optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+ optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+}
+
+/* ZSTD_initStats_ultra():
+ * make a first compression pass, just to seed stats with more accurate starting values.
+ * only works on first block, with no dictionary and no ldm.
+ * this function cannot error, hence its constract must be respected.
+ */
+static void
+ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
+ seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */
+ memcpy(tmpRep, rep, sizeof(tmpRep));
+
+ DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
+ assert(ms->opt.litLengthSum == 0); /* first block */
+ assert(seqStore->sequences == seqStore->sequencesStart); /* no ldm */
+ assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */
+ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */
+
+ ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/
+
+ /* invalidate first scan from history */
+ ZSTD_resetSeqStore(seqStore);
+ ms->window.base -= srcSize;
+ ms->window.dictLimit += (U32)srcSize;
+ ms->window.lowLimit = ms->window.dictLimit;
+ ms->nextToUpdate = ms->window.dictLimit;
+ ms->nextToUpdate3 = ms->window.dictLimit;
+
+ /* re-inforce weight of collected statistics */
+ ZSTD_upscaleStats(&ms->opt);
+}
+
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btultra2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ U32 const current = (U32)((const BYTE*)src - ms->window.base);
+ DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
+
+ /* 2-pass strategy:
+ * this strategy makes a first pass over first block to collect statistics
+ * and seed next round's statistics with it.
+ * After 1st pass, function forgets everything, and starts a new block.
+ * Consequently, this can only work if no data has been previously loaded in tables,
+ * aka, no dictionary, no prefix, no ldm preprocessing.
+ * The compression ratio gain is generally small (~0.5% on first block),
+ * the cost is 2x cpu time on first block. */
+ assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+ if ( (ms->opt.litLengthSum==0) /* first block */
+ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
+ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */
+ && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */
+ && (srcSize > ZSTD_PREDEF_THRESHOLD)
+ ) {
+ ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
+ }
+
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
+}
+
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
+}
+
+/* note : no btultra2 variant for extDict nor dictMatchState,
+ * because btultra2 is not meant to work with dictionaries
+ * and is only specific for the first block (no prefix) */
diff --git a/Utilities/cmzstd/lib/compress/zstd_opt.h b/Utilities/cmzstd/lib/compress/zstd_opt.h
new file mode 100644
index 000000000..094f74766
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_opt.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_OPT_H
+#define ZSTD_OPT_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+/* used in ZSTD_loadDictionaryContent() */
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
+
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+ /* note : no btultra2 variant for extDict nor dictMatchState,
+ * because btultra2 is not meant to work with dictionaries
+ * and is only specific for the first block (no prefix) */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_OPT_H */
diff --git a/Utilities/cmzstd/lib/compress/zstdmt_compress.c b/Utilities/cmzstd/lib/compress/zstdmt_compress.c
new file mode 100644
index 000000000..2cbd6ffad
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstdmt_compress.c
@@ -0,0 +1,2107 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ====== Compiler specifics ====== */
+#if defined(_MSC_VER)
+# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+/* ====== Constants ====== */
+#define ZSTDMT_OVERLAPLOG_DEFAULT 0
+
+
+/* ====== Dependencies ====== */
+#include <string.h> /* memcpy, memset */
+#include <limits.h> /* INT_MAX, UINT_MAX */
+#include "pool.h" /* threadpool */
+#include "threading.h" /* mutex */
+#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
+#include "zstd_ldm.h"
+#include "zstdmt_compress.h"
+
+/* Guards code to support resizing the SeqPool.
+ * We will want to resize the SeqPool to save memory in the future.
+ * Until then, comment the code out since it is unused.
+ */
+#define ZSTD_RESIZE_SEQPOOL 0
+
+/* ====== Debug ====== */
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2) \
+ && !defined(_MSC_VER) \
+ && !defined(__MINGW32__)
+
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/times.h>
+
+# define DEBUG_PRINTHEX(l,p,n) { \
+ unsigned debug_u; \
+ for (debug_u=0; debug_u<(n); debug_u++) \
+ RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
+ RAWLOG(l, " \n"); \
+}
+
+static unsigned long long GetCurrentClockTimeMicroseconds(void)
+{
+ static clock_t _ticksPerSecond = 0;
+ if (_ticksPerSecond <= 0) _ticksPerSecond = sysconf(_SC_CLK_TCK);
+
+ { struct tms junk; clock_t newTicks = (clock_t) times(&junk);
+ return ((((unsigned long long)newTicks)*(1000000))/_ticksPerSecond);
+} }
+
+#define MUTEX_WAIT_TIME_DLEVEL 6
+#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \
+ if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
+ unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
+ ZSTD_pthread_mutex_lock(mutex); \
+ { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
+ unsigned long long const elapsedTime = (afterTime-beforeTime); \
+ if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \
+ DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
+ elapsedTime, #mutex); \
+ } } \
+ } else { \
+ ZSTD_pthread_mutex_lock(mutex); \
+ } \
+}
+
+#else
+
+# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
+# define DEBUG_PRINTHEX(l,p,n) {}
+
+#endif
+
+
+/* ===== Buffer Pool ===== */
+/* a single Buffer Pool can be invoked from multiple threads in parallel */
+
+typedef struct buffer_s {
+ void* start;
+ size_t capacity;
+} buffer_t;
+
+static const buffer_t g_nullBuffer = { NULL, 0 };
+
+typedef struct ZSTDMT_bufferPool_s {
+ ZSTD_pthread_mutex_t poolMutex;
+ size_t bufferSize;
+ unsigned totalBuffers;
+ unsigned nbBuffers;
+ ZSTD_customMem cMem;
+ buffer_t bTable[1]; /* variable size */
+} ZSTDMT_bufferPool;
+
+static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+ unsigned const maxNbBuffers = 2*nbWorkers + 3;
+ ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
+ sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
+ if (bufPool==NULL) return NULL;
+ if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
+ ZSTD_free(bufPool, cMem);
+ return NULL;
+ }
+ bufPool->bufferSize = 64 KB;
+ bufPool->totalBuffers = maxNbBuffers;
+ bufPool->nbBuffers = 0;
+ bufPool->cMem = cMem;
+ return bufPool;
+}
+
+static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
+{
+ unsigned u;
+ DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
+ if (!bufPool) return; /* compatibility with free on NULL */
+ for (u=0; u<bufPool->totalBuffers; u++) {
+ DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start);
+ ZSTD_free(bufPool->bTable[u].start, bufPool->cMem);
+ }
+ ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
+ ZSTD_free(bufPool, bufPool->cMem);
+}
+
+/* only works at initialization, not during compression */
+static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
+{
+ size_t const poolSize = sizeof(*bufPool)
+ + (bufPool->totalBuffers - 1) * sizeof(buffer_t);
+ unsigned u;
+ size_t totalBufferSize = 0;
+ ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+ for (u=0; u<bufPool->totalBuffers; u++)
+ totalBufferSize += bufPool->bTable[u].capacity;
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+
+ return poolSize + totalBufferSize;
+}
+
+/* ZSTDMT_setBufferSize() :
+ * all future buffers provided by this buffer pool will have _at least_ this size
+ * note : it's better for all buffers to have same size,
+ * as they become freely interchangeable, reducing malloc/free usages and memory fragmentation */
+static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize)
+{
+ ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+ DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize);
+ bufPool->bufferSize = bSize;
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+}
+
+
+static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, U32 nbWorkers)
+{
+ unsigned const maxNbBuffers = 2*nbWorkers + 3;
+ if (srcBufPool==NULL) return NULL;
+ if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */
+ return srcBufPool;
+ /* need a larger buffer pool */
+ { ZSTD_customMem const cMem = srcBufPool->cMem;
+ size_t const bSize = srcBufPool->bufferSize; /* forward parameters */
+ ZSTDMT_bufferPool* newBufPool;
+ ZSTDMT_freeBufferPool(srcBufPool);
+ newBufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+ if (newBufPool==NULL) return newBufPool;
+ ZSTDMT_setBufferSize(newBufPool, bSize);
+ return newBufPool;
+ }
+}
+
+/** ZSTDMT_getBuffer() :
+ * assumption : bufPool must be valid
+ * @return : a buffer, with start pointer and size
+ * note: allocation may fail, in this case, start==NULL and size==0 */
+static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
+{
+ size_t const bSize = bufPool->bufferSize;
+ DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize);
+ ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+ if (bufPool->nbBuffers) { /* try to use an existing buffer */
+ buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
+ size_t const availBufferSize = buf.capacity;
+ bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
+ if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
+ /* large enough, but not too much */
+ DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
+ bufPool->nbBuffers, (U32)buf.capacity);
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+ return buf;
+ }
+ /* size conditions not respected : scratch this buffer, create new one */
+ DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing");
+ ZSTD_free(buf.start, bufPool->cMem);
+ }
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+ /* create new buffer */
+ DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer");
+ { buffer_t buffer;
+ void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+ buffer.start = start; /* note : start can be NULL if malloc fails ! */
+ buffer.capacity = (start==NULL) ? 0 : bSize;
+ if (start==NULL) {
+ DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!");
+ } else {
+ DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
+ }
+ return buffer;
+ }
+}
+
+#if ZSTD_RESIZE_SEQPOOL
+/** ZSTDMT_resizeBuffer() :
+ * assumption : bufPool must be valid
+ * @return : a buffer that is at least the buffer pool buffer size.
+ * If a reallocation happens, the data in the input buffer is copied.
+ */
+static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer)
+{
+ size_t const bSize = bufPool->bufferSize;
+ if (buffer.capacity < bSize) {
+ void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+ buffer_t newBuffer;
+ newBuffer.start = start;
+ newBuffer.capacity = start == NULL ? 0 : bSize;
+ if (start != NULL) {
+ assert(newBuffer.capacity >= buffer.capacity);
+ memcpy(newBuffer.start, buffer.start, buffer.capacity);
+ DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize);
+ return newBuffer;
+ }
+ DEBUGLOG(5, "ZSTDMT_resizeBuffer: buffer allocation failure !!");
+ }
+ return buffer;
+}
+#endif
+
+/* store buffer for later re-use, up to pool capacity */
+static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
+{
+ DEBUGLOG(5, "ZSTDMT_releaseBuffer");
+ if (buf.start == NULL) return; /* compatible with release on NULL */
+ ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+ if (bufPool->nbBuffers < bufPool->totalBuffers) {
+ bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
+ DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
+ (U32)buf.capacity, (U32)(bufPool->nbBuffers-1));
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+ return;
+ }
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+ /* Reached bufferPool capacity (should not happen) */
+ DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing ");
+ ZSTD_free(buf.start, bufPool->cMem);
+}
+
+
+/* ===== Seq Pool Wrapper ====== */
+
+static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0};
+
+typedef ZSTDMT_bufferPool ZSTDMT_seqPool;
+
+static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool)
+{
+ return ZSTDMT_sizeof_bufferPool(seqPool);
+}
+
+static rawSeqStore_t bufferToSeq(buffer_t buffer)
+{
+ rawSeqStore_t seq = {NULL, 0, 0, 0};
+ seq.seq = (rawSeq*)buffer.start;
+ seq.capacity = buffer.capacity / sizeof(rawSeq);
+ return seq;
+}
+
+static buffer_t seqToBuffer(rawSeqStore_t seq)
+{
+ buffer_t buffer;
+ buffer.start = seq.seq;
+ buffer.capacity = seq.capacity * sizeof(rawSeq);
+ return buffer;
+}
+
+static rawSeqStore_t ZSTDMT_getSeq(ZSTDMT_seqPool* seqPool)
+{
+ if (seqPool->bufferSize == 0) {
+ return kNullRawSeqStore;
+ }
+ return bufferToSeq(ZSTDMT_getBuffer(seqPool));
+}
+
+#if ZSTD_RESIZE_SEQPOOL
+static rawSeqStore_t ZSTDMT_resizeSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
+{
+ return bufferToSeq(ZSTDMT_resizeBuffer(seqPool, seqToBuffer(seq)));
+}
+#endif
+
+static void ZSTDMT_releaseSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
+{
+ ZSTDMT_releaseBuffer(seqPool, seqToBuffer(seq));
+}
+
+static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq)
+{
+ ZSTDMT_setBufferSize(seqPool, nbSeq * sizeof(rawSeq));
+}
+
+static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+ ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+ if (seqPool == NULL) return NULL;
+ ZSTDMT_setNbSeq(seqPool, 0);
+ return seqPool;
+}
+
+static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool)
+{
+ ZSTDMT_freeBufferPool(seqPool);
+}
+
+static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers)
+{
+ return ZSTDMT_expandBufferPool(pool, nbWorkers);
+}
+
+
+/* ===== CCtx Pool ===== */
+/* a single CCtx Pool can be invoked from multiple threads in parallel */
+
+typedef struct {
+ ZSTD_pthread_mutex_t poolMutex;
+ int totalCCtx;
+ int availCCtx;
+ ZSTD_customMem cMem;
+ ZSTD_CCtx* cctx[1]; /* variable size */
+} ZSTDMT_CCtxPool;
+
+/* note : all CCtx borrowed from the pool should be released back to the pool _before_ freeing the pool */
+static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
+{
+ int cid;
+ for (cid=0; cid<pool->totalCCtx; cid++)
+ ZSTD_freeCCtx(pool->cctx[cid]); /* note : compatible with free on NULL */
+ ZSTD_pthread_mutex_destroy(&pool->poolMutex);
+ ZSTD_free(pool, pool->cMem);
+}
+
+/* ZSTDMT_createCCtxPool() :
+ * implies nbWorkers >= 1 , checked by caller ZSTDMT_createCCtx() */
+static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers,
+ ZSTD_customMem cMem)
+{
+ ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
+ sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem);
+ assert(nbWorkers > 0);
+ if (!cctxPool) return NULL;
+ if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
+ ZSTD_free(cctxPool, cMem);
+ return NULL;
+ }
+ cctxPool->cMem = cMem;
+ cctxPool->totalCCtx = nbWorkers;
+ cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */
+ cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem);
+ if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
+ DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers);
+ return cctxPool;
+}
+
+static ZSTDMT_CCtxPool* ZSTDMT_expandCCtxPool(ZSTDMT_CCtxPool* srcPool,
+ int nbWorkers)
+{
+ if (srcPool==NULL) return NULL;
+ if (nbWorkers <= srcPool->totalCCtx) return srcPool; /* good enough */
+ /* need a larger cctx pool */
+ { ZSTD_customMem const cMem = srcPool->cMem;
+ ZSTDMT_freeCCtxPool(srcPool);
+ return ZSTDMT_createCCtxPool(nbWorkers, cMem);
+ }
+}
+
+/* only works during initialization phase, not during compression */
+static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
+{
+ ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
+ { unsigned const nbWorkers = cctxPool->totalCCtx;
+ size_t const poolSize = sizeof(*cctxPool)
+ + (nbWorkers-1) * sizeof(ZSTD_CCtx*);
+ unsigned u;
+ size_t totalCCtxSize = 0;
+ for (u=0; u<nbWorkers; u++) {
+ totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
+ }
+ ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+ assert(nbWorkers > 0);
+ return poolSize + totalCCtxSize;
+ }
+}
+
+static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
+{
+ DEBUGLOG(5, "ZSTDMT_getCCtx");
+ ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
+ if (cctxPool->availCCtx) {
+ cctxPool->availCCtx--;
+ { ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx];
+ ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+ return cctx;
+ } }
+ ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+ DEBUGLOG(5, "create one more CCtx");
+ return ZSTD_createCCtx_advanced(cctxPool->cMem); /* note : can be NULL, when creation fails ! */
+}
+
+static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
+{
+ if (cctx==NULL) return; /* compatibility with release on NULL */
+ ZSTD_pthread_mutex_lock(&pool->poolMutex);
+ if (pool->availCCtx < pool->totalCCtx)
+ pool->cctx[pool->availCCtx++] = cctx;
+ else {
+ /* pool overflow : should not happen, since totalCCtx==nbWorkers */
+ DEBUGLOG(4, "CCtx pool overflow : free cctx");
+ ZSTD_freeCCtx(cctx);
+ }
+ ZSTD_pthread_mutex_unlock(&pool->poolMutex);
+}
+
+/* ==== Serial State ==== */
+
+typedef struct {
+ void const* start;
+ size_t size;
+} range_t;
+
+typedef struct {
+ /* All variables in the struct are protected by mutex. */
+ ZSTD_pthread_mutex_t mutex;
+ ZSTD_pthread_cond_t cond;
+ ZSTD_CCtx_params params;
+ ldmState_t ldmState;
+ XXH64_state_t xxhState;
+ unsigned nextJobID;
+ /* Protects ldmWindow.
+ * Must be acquired after the main mutex when acquiring both.
+ */
+ ZSTD_pthread_mutex_t ldmWindowMutex;
+ ZSTD_pthread_cond_t ldmWindowCond; /* Signaled when ldmWindow is udpated */
+ ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */
+} serialState_t;
+
+static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params, size_t jobSize)
+{
+ /* Adjust parameters */
+ if (params.ldmParams.enableLdm) {
+ DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10);
+ ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
+ assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
+ assert(params.ldmParams.hashRateLog < 32);
+ serialState->ldmState.hashPower =
+ ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+ } else {
+ memset(&params.ldmParams, 0, sizeof(params.ldmParams));
+ }
+ serialState->nextJobID = 0;
+ if (params.fParams.checksumFlag)
+ XXH64_reset(&serialState->xxhState, 0);
+ if (params.ldmParams.enableLdm) {
+ ZSTD_customMem cMem = params.customMem;
+ unsigned const hashLog = params.ldmParams.hashLog;
+ size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
+ unsigned const bucketLog =
+ params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
+ size_t const bucketSize = (size_t)1 << bucketLog;
+ unsigned const prevBucketLog =
+ serialState->params.ldmParams.hashLog -
+ serialState->params.ldmParams.bucketSizeLog;
+ /* Size the seq pool tables */
+ ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
+ /* Reset the window */
+ ZSTD_window_clear(&serialState->ldmState.window);
+ serialState->ldmWindow = serialState->ldmState.window;
+ /* Resize tables and output space if necessary. */
+ if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) {
+ ZSTD_free(serialState->ldmState.hashTable, cMem);
+ serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem);
+ }
+ if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
+ ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
+ serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem);
+ }
+ if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
+ return 1;
+ /* Zero the tables */
+ memset(serialState->ldmState.hashTable, 0, hashSize);
+ memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
+ }
+ serialState->params = params;
+ serialState->params.jobSize = (U32)jobSize;
+ return 0;
+}
+
+static int ZSTDMT_serialState_init(serialState_t* serialState)
+{
+ int initError = 0;
+ memset(serialState, 0, sizeof(*serialState));
+ initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL);
+ initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL);
+ initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL);
+ initError |= ZSTD_pthread_cond_init(&serialState->ldmWindowCond, NULL);
+ return initError;
+}
+
+static void ZSTDMT_serialState_free(serialState_t* serialState)
+{
+ ZSTD_customMem cMem = serialState->params.customMem;
+ ZSTD_pthread_mutex_destroy(&serialState->mutex);
+ ZSTD_pthread_cond_destroy(&serialState->cond);
+ ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex);
+ ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond);
+ ZSTD_free(serialState->ldmState.hashTable, cMem);
+ ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
+}
+
+static void ZSTDMT_serialState_update(serialState_t* serialState,
+ ZSTD_CCtx* jobCCtx, rawSeqStore_t seqStore,
+ range_t src, unsigned jobID)
+{
+ /* Wait for our turn */
+ ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
+ while (serialState->nextJobID < jobID) {
+ DEBUGLOG(5, "wait for serialState->cond");
+ ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex);
+ }
+ /* A future job may error and skip our job */
+ if (serialState->nextJobID == jobID) {
+ /* It is now our turn, do any processing necessary */
+ if (serialState->params.ldmParams.enableLdm) {
+ size_t error;
+ assert(seqStore.seq != NULL && seqStore.pos == 0 &&
+ seqStore.size == 0 && seqStore.capacity > 0);
+ assert(src.size <= serialState->params.jobSize);
+ ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
+ error = ZSTD_ldm_generateSequences(
+ &serialState->ldmState, &seqStore,
+ &serialState->params.ldmParams, src.start, src.size);
+ /* We provide a large enough buffer to never fail. */
+ assert(!ZSTD_isError(error)); (void)error;
+ /* Update ldmWindow to match the ldmState.window and signal the main
+ * thread if it is waiting for a buffer.
+ */
+ ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
+ serialState->ldmWindow = serialState->ldmState.window;
+ ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
+ ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
+ }
+ if (serialState->params.fParams.checksumFlag && src.size > 0)
+ XXH64_update(&serialState->xxhState, src.start, src.size);
+ }
+ /* Now it is the next jobs turn */
+ serialState->nextJobID++;
+ ZSTD_pthread_cond_broadcast(&serialState->cond);
+ ZSTD_pthread_mutex_unlock(&serialState->mutex);
+
+ if (seqStore.size > 0) {
+ size_t const err = ZSTD_referenceExternalSequences(
+ jobCCtx, seqStore.seq, seqStore.size);
+ assert(serialState->params.ldmParams.enableLdm);
+ assert(!ZSTD_isError(err));
+ (void)err;
+ }
+}
+
+static void ZSTDMT_serialState_ensureFinished(serialState_t* serialState,
+ unsigned jobID, size_t cSize)
+{
+ ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
+ if (serialState->nextJobID <= jobID) {
+ assert(ZSTD_isError(cSize)); (void)cSize;
+ DEBUGLOG(5, "Skipping past job %u because of error", jobID);
+ serialState->nextJobID = jobID + 1;
+ ZSTD_pthread_cond_broadcast(&serialState->cond);
+
+ ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
+ ZSTD_window_clear(&serialState->ldmWindow);
+ ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
+ ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
+ }
+ ZSTD_pthread_mutex_unlock(&serialState->mutex);
+
+}
+
+
+/* ------------------------------------------ */
+/* ===== Worker thread ===== */
+/* ------------------------------------------ */
+
+static const range_t kNullRange = { NULL, 0 };
+
+typedef struct {
+ size_t consumed; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx */
+ size_t cSize; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx, then set0 by mtctx */
+ ZSTD_pthread_mutex_t job_mutex; /* Thread-safe - used by mtctx and worker */
+ ZSTD_pthread_cond_t job_cond; /* Thread-safe - used by mtctx and worker */
+ ZSTDMT_CCtxPool* cctxPool; /* Thread-safe - used by mtctx and (all) workers */
+ ZSTDMT_bufferPool* bufPool; /* Thread-safe - used by mtctx and (all) workers */
+ ZSTDMT_seqPool* seqPool; /* Thread-safe - used by mtctx and (all) workers */
+ serialState_t* serial; /* Thread-safe - used by mtctx and (all) workers */
+ buffer_t dstBuff; /* set by worker (or mtctx), then read by worker & mtctx, then modified by mtctx => no barrier */
+ range_t prefix; /* set by mtctx, then read by worker & mtctx => no barrier */
+ range_t src; /* set by mtctx, then read by worker & mtctx => no barrier */
+ unsigned jobID; /* set by mtctx, then read by worker => no barrier */
+ unsigned firstJob; /* set by mtctx, then read by worker => no barrier */
+ unsigned lastJob; /* set by mtctx, then read by worker => no barrier */
+ ZSTD_CCtx_params params; /* set by mtctx, then read by worker => no barrier */
+ const ZSTD_CDict* cdict; /* set by mtctx, then read by worker => no barrier */
+ unsigned long long fullFrameSize; /* set by mtctx, then read by worker => no barrier */
+ size_t dstFlushed; /* used only by mtctx */
+ unsigned frameChecksumNeeded; /* used only by mtctx */
+} ZSTDMT_jobDescription;
+
+#define JOB_ERROR(e) { \
+ ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
+ job->cSize = e; \
+ ZSTD_pthread_mutex_unlock(&job->job_mutex); \
+ goto _endJob; \
+}
+
+/* ZSTDMT_compressionJob() is a POOL_function type */
+static void ZSTDMT_compressionJob(void* jobDescription)
+{
+ ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
+ ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */
+ ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
+ rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool);
+ buffer_t dstBuff = job->dstBuff;
+ size_t lastCBlockSize = 0;
+
+ /* ressources */
+ if (cctx==NULL) JOB_ERROR(ERROR(memory_allocation));
+ if (dstBuff.start == NULL) { /* streaming job : doesn't provide a dstBuffer */
+ dstBuff = ZSTDMT_getBuffer(job->bufPool);
+ if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation));
+ job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */
+ }
+ if (jobParams.ldmParams.enableLdm && rawSeqStore.seq == NULL)
+ JOB_ERROR(ERROR(memory_allocation));
+
+ /* Don't compute the checksum for chunks, since we compute it externally,
+ * but write it in the header.
+ */
+ if (job->jobID != 0) jobParams.fParams.checksumFlag = 0;
+ /* Don't run LDM for the chunks, since we handle it externally */
+ jobParams.ldmParams.enableLdm = 0;
+
+
+ /* init */
+ if (job->cdict) {
+ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, job->cdict, jobParams, job->fullFrameSize);
+ assert(job->firstJob); /* only allowed for first job */
+ if (ZSTD_isError(initError)) JOB_ERROR(initError);
+ } else { /* srcStart points at reloaded section */
+ U64 const pledgedSrcSize = job->firstJob ? job->fullFrameSize : job->src.size;
+ { size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob);
+ if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError);
+ }
+ { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
+ job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
+ ZSTD_dtlm_fast,
+ NULL, /*cdict*/
+ jobParams, pledgedSrcSize);
+ if (ZSTD_isError(initError)) JOB_ERROR(initError);
+ } }
+
+ /* Perform serial step as early as possible, but after CCtx initialization */
+ ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID);
+
+ if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */
+ size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0);
+ if (ZSTD_isError(hSize)) JOB_ERROR(hSize);
+ DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize);
+ ZSTD_invalidateRepCodes(cctx);
+ }
+
+ /* compress */
+ { size_t const chunkSize = 4*ZSTD_BLOCKSIZE_MAX;
+ int const nbChunks = (int)((job->src.size + (chunkSize-1)) / chunkSize);
+ const BYTE* ip = (const BYTE*) job->src.start;
+ BYTE* const ostart = (BYTE*)dstBuff.start;
+ BYTE* op = ostart;
+ BYTE* oend = op + dstBuff.capacity;
+ int chunkNb;
+ if (sizeof(size_t) > sizeof(int)) assert(job->src.size < ((size_t)INT_MAX) * chunkSize); /* check overflow */
+ DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks);
+ assert(job->cSize == 0);
+ for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) {
+ size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, chunkSize);
+ if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
+ ip += chunkSize;
+ op += cSize; assert(op < oend);
+ /* stats */
+ ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
+ job->cSize += cSize;
+ job->consumed = chunkSize * chunkNb;
+ DEBUGLOG(5, "ZSTDMT_compressionJob: compress new block : cSize==%u bytes (total: %u)",
+ (U32)cSize, (U32)job->cSize);
+ ZSTD_pthread_cond_signal(&job->job_cond); /* warns some more data is ready to be flushed */
+ ZSTD_pthread_mutex_unlock(&job->job_mutex);
+ }
+ /* last block */
+ assert(chunkSize > 0);
+ assert((chunkSize & (chunkSize - 1)) == 0); /* chunkSize must be power of 2 for mask==(chunkSize-1) to work */
+ if ((nbChunks > 0) | job->lastJob /*must output a "last block" flag*/ ) {
+ size_t const lastBlockSize1 = job->src.size & (chunkSize-1);
+ size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1;
+ size_t const cSize = (job->lastJob) ?
+ ZSTD_compressEnd (cctx, op, oend-op, ip, lastBlockSize) :
+ ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize);
+ if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
+ lastCBlockSize = cSize;
+ } }
+
+_endJob:
+ ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize);
+ if (job->prefix.size > 0)
+ DEBUGLOG(5, "Finished with prefix: %zx", (size_t)job->prefix.start);
+ DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start);
+ /* release resources */
+ ZSTDMT_releaseSeq(job->seqPool, rawSeqStore);
+ ZSTDMT_releaseCCtx(job->cctxPool, cctx);
+ /* report */
+ ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
+ if (ZSTD_isError(job->cSize)) assert(lastCBlockSize == 0);
+ job->cSize += lastCBlockSize;
+ job->consumed = job->src.size; /* when job->consumed == job->src.size , compression job is presumed completed */
+ ZSTD_pthread_cond_signal(&job->job_cond);
+ ZSTD_pthread_mutex_unlock(&job->job_mutex);
+}
+
+
+/* ------------------------------------------ */
+/* ===== Multi-threaded compression ===== */
+/* ------------------------------------------ */
+
+typedef struct {
+ range_t prefix; /* read-only non-owned prefix buffer */
+ buffer_t buffer;
+ size_t filled;
+} inBuff_t;
+
+typedef struct {
+ BYTE* buffer; /* The round input buffer. All jobs get references
+ * to pieces of the buffer. ZSTDMT_tryGetInputRange()
+ * handles handing out job input buffers, and makes
+ * sure it doesn't overlap with any pieces still in use.
+ */
+ size_t capacity; /* The capacity of buffer. */
+ size_t pos; /* The position of the current inBuff in the round
+ * buffer. Updated past the end if the inBuff once
+ * the inBuff is sent to the worker thread.
+ * pos <= capacity.
+ */
+} roundBuff_t;
+
+static const roundBuff_t kNullRoundBuff = {NULL, 0, 0};
+
+#define RSYNC_LENGTH 32
+
+typedef struct {
+ U64 hash;
+ U64 hitMask;
+ U64 primePower;
+} rsyncState_t;
+
+struct ZSTDMT_CCtx_s {
+ POOL_ctx* factory;
+ ZSTDMT_jobDescription* jobs;
+ ZSTDMT_bufferPool* bufPool;
+ ZSTDMT_CCtxPool* cctxPool;
+ ZSTDMT_seqPool* seqPool;
+ ZSTD_CCtx_params params;
+ size_t targetSectionSize;
+ size_t targetPrefixSize;
+ int jobReady; /* 1 => one job is already prepared, but pool has shortage of workers. Don't create a new job. */
+ inBuff_t inBuff;
+ roundBuff_t roundBuff;
+ serialState_t serial;
+ rsyncState_t rsync;
+ unsigned singleBlockingThread;
+ unsigned jobIDMask;
+ unsigned doneJobID;
+ unsigned nextJobID;
+ unsigned frameEnded;
+ unsigned allJobsCompleted;
+ unsigned long long frameContentSize;
+ unsigned long long consumed;
+ unsigned long long produced;
+ ZSTD_customMem cMem;
+ ZSTD_CDict* cdictLocal;
+ const ZSTD_CDict* cdict;
+};
+
+static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem)
+{
+ U32 jobNb;
+ if (jobTable == NULL) return;
+ for (jobNb=0; jobNb<nbJobs; jobNb++) {
+ ZSTD_pthread_mutex_destroy(&jobTable[jobNb].job_mutex);
+ ZSTD_pthread_cond_destroy(&jobTable[jobNb].job_cond);
+ }
+ ZSTD_free(jobTable, cMem);
+}
+
+/* ZSTDMT_allocJobsTable()
+ * allocate and init a job table.
+ * update *nbJobsPtr to next power of 2 value, as size of table */
+static ZSTDMT_jobDescription* ZSTDMT_createJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem)
+{
+ U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1;
+ U32 const nbJobs = 1 << nbJobsLog2;
+ U32 jobNb;
+ ZSTDMT_jobDescription* const jobTable = (ZSTDMT_jobDescription*)
+ ZSTD_calloc(nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
+ int initError = 0;
+ if (jobTable==NULL) return NULL;
+ *nbJobsPtr = nbJobs;
+ for (jobNb=0; jobNb<nbJobs; jobNb++) {
+ initError |= ZSTD_pthread_mutex_init(&jobTable[jobNb].job_mutex, NULL);
+ initError |= ZSTD_pthread_cond_init(&jobTable[jobNb].job_cond, NULL);
+ }
+ if (initError != 0) {
+ ZSTDMT_freeJobsTable(jobTable, nbJobs, cMem);
+ return NULL;
+ }
+ return jobTable;
+}
+
+static size_t ZSTDMT_expandJobsTable (ZSTDMT_CCtx* mtctx, U32 nbWorkers) {
+ U32 nbJobs = nbWorkers + 2;
+ if (nbJobs > mtctx->jobIDMask+1) { /* need more job capacity */
+ ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
+ mtctx->jobIDMask = 0;
+ mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, mtctx->cMem);
+ if (mtctx->jobs==NULL) return ERROR(memory_allocation);
+ assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0)); /* ensure nbJobs is a power of 2 */
+ mtctx->jobIDMask = nbJobs - 1;
+ }
+ return 0;
+}
+
+
+/* ZSTDMT_CCtxParam_setNbWorkers():
+ * Internal use only */
+size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
+{
+ if (nbWorkers > ZSTDMT_NBWORKERS_MAX) nbWorkers = ZSTDMT_NBWORKERS_MAX;
+ params->nbWorkers = nbWorkers;
+ params->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT;
+ params->jobSize = 0;
+ return nbWorkers;
+}
+
+ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+ ZSTDMT_CCtx* mtctx;
+ U32 nbJobs = nbWorkers + 2;
+ int initError;
+ DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbWorkers = %u)", nbWorkers);
+
+ if (nbWorkers < 1) return NULL;
+ nbWorkers = MIN(nbWorkers , ZSTDMT_NBWORKERS_MAX);
+ if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL))
+ /* invalid custom allocator */
+ return NULL;
+
+ mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
+ if (!mtctx) return NULL;
+ ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
+ mtctx->cMem = cMem;
+ mtctx->allJobsCompleted = 1;
+ mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem);
+ mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem);
+ assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */
+ mtctx->jobIDMask = nbJobs - 1;
+ mtctx->bufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+ mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem);
+ mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem);
+ initError = ZSTDMT_serialState_init(&mtctx->serial);
+ mtctx->roundBuff = kNullRoundBuff;
+ if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool | !mtctx->seqPool | initError) {
+ ZSTDMT_freeCCtx(mtctx);
+ return NULL;
+ }
+ DEBUGLOG(3, "mt_cctx created, for %u threads", nbWorkers);
+ return mtctx;
+}
+
+ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers)
+{
+ return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem);
+}
+
+
+/* ZSTDMT_releaseAllJobResources() :
+ * note : ensure all workers are killed first ! */
+static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
+{
+ unsigned jobID;
+ DEBUGLOG(3, "ZSTDMT_releaseAllJobResources");
+ for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) {
+ DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start);
+ ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
+ mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+ mtctx->jobs[jobID].cSize = 0;
+ }
+ memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription));
+ mtctx->inBuff.buffer = g_nullBuffer;
+ mtctx->inBuff.filled = 0;
+ mtctx->allJobsCompleted = 1;
+}
+
+static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx)
+{
+ DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
+ while (mtctx->doneJobID < mtctx->nextJobID) {
+ unsigned const jobID = mtctx->doneJobID & mtctx->jobIDMask;
+ ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
+ while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
+ DEBUGLOG(4, "waiting for jobCompleted signal from job %u", mtctx->doneJobID); /* we want to block when waiting for data to flush */
+ ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
+ }
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
+ mtctx->doneJobID++;
+ }
+}
+
+size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
+{
+ if (mtctx==NULL) return 0; /* compatible with free on NULL */
+ POOL_free(mtctx->factory); /* stop and free worker threads */
+ ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */
+ ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
+ ZSTDMT_freeBufferPool(mtctx->bufPool);
+ ZSTDMT_freeCCtxPool(mtctx->cctxPool);
+ ZSTDMT_freeSeqPool(mtctx->seqPool);
+ ZSTDMT_serialState_free(&mtctx->serial);
+ ZSTD_freeCDict(mtctx->cdictLocal);
+ if (mtctx->roundBuff.buffer)
+ ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
+ ZSTD_free(mtctx, mtctx->cMem);
+ return 0;
+}
+
+size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
+{
+ if (mtctx == NULL) return 0; /* supports sizeof NULL */
+ return sizeof(*mtctx)
+ + POOL_sizeof(mtctx->factory)
+ + ZSTDMT_sizeof_bufferPool(mtctx->bufPool)
+ + (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription)
+ + ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool)
+ + ZSTDMT_sizeof_seqPool(mtctx->seqPool)
+ + ZSTD_sizeof_CDict(mtctx->cdictLocal)
+ + mtctx->roundBuff.capacity;
+}
+
+/* Internal only */
+size_t
+ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
+ ZSTDMT_parameter parameter,
+ int value)
+{
+ DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter");
+ switch(parameter)
+ {
+ case ZSTDMT_p_jobSize :
+ DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %i", value);
+ if ( value != 0 /* default */
+ && value < ZSTDMT_JOBSIZE_MIN)
+ value = ZSTDMT_JOBSIZE_MIN;
+ assert(value >= 0);
+ if (value > ZSTDMT_JOBSIZE_MAX) value = ZSTDMT_JOBSIZE_MAX;
+ params->jobSize = value;
+ return value;
+
+ case ZSTDMT_p_overlapLog :
+ DEBUGLOG(4, "ZSTDMT_p_overlapLog : %i", value);
+ if (value < ZSTD_OVERLAPLOG_MIN) value = ZSTD_OVERLAPLOG_MIN;
+ if (value > ZSTD_OVERLAPLOG_MAX) value = ZSTD_OVERLAPLOG_MAX;
+ params->overlapLog = value;
+ return value;
+
+ case ZSTDMT_p_rsyncable :
+ value = (value != 0);
+ params->rsyncable = value;
+ return value;
+
+ default :
+ return ERROR(parameter_unsupported);
+ }
+}
+
+size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value)
+{
+ DEBUGLOG(4, "ZSTDMT_setMTCtxParameter");
+ return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
+}
+
+size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value)
+{
+ switch (parameter) {
+ case ZSTDMT_p_jobSize:
+ assert(mtctx->params.jobSize <= INT_MAX);
+ *value = (int)(mtctx->params.jobSize);
+ break;
+ case ZSTDMT_p_overlapLog:
+ *value = mtctx->params.overlapLog;
+ break;
+ case ZSTDMT_p_rsyncable:
+ *value = mtctx->params.rsyncable;
+ break;
+ default:
+ return ERROR(parameter_unsupported);
+ }
+ return 0;
+}
+
+/* Sets parameters relevant to the compression job,
+ * initializing others to default values. */
+static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(ZSTD_CCtx_params const params)
+{
+ ZSTD_CCtx_params jobParams;
+ memset(&jobParams, 0, sizeof(jobParams));
+
+ jobParams.cParams = params.cParams;
+ jobParams.fParams = params.fParams;
+ jobParams.compressionLevel = params.compressionLevel;
+
+ return jobParams;
+}
+
+
+/* ZSTDMT_resize() :
+ * @return : error code if fails, 0 on success */
+static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers)
+{
+ if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation);
+ CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbWorkers) );
+ mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, nbWorkers);
+ if (mtctx->bufPool == NULL) return ERROR(memory_allocation);
+ mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers);
+ if (mtctx->cctxPool == NULL) return ERROR(memory_allocation);
+ mtctx->seqPool = ZSTDMT_expandSeqPool(mtctx->seqPool, nbWorkers);
+ if (mtctx->seqPool == NULL) return ERROR(memory_allocation);
+ ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
+ return 0;
+}
+
+
+/*! ZSTDMT_updateCParams_whileCompressing() :
+ * Updates a selected set of compression parameters, remaining compatible with currently active frame.
+ * New parameters will be applied to next compression job. */
+void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams)
+{
+ U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */
+ int const compressionLevel = cctxParams->compressionLevel;
+ DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)",
+ compressionLevel);
+ mtctx->params.compressionLevel = compressionLevel;
+ { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, 0, 0);
+ cParams.windowLog = saved_wlog;
+ mtctx->params.cParams = cParams;
+ }
+}
+
+/* ZSTDMT_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads.
+ * Note : mutex will be acquired during statistics collection inside workers. */
+ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
+{
+ ZSTD_frameProgression fps;
+ DEBUGLOG(5, "ZSTDMT_getFrameProgression");
+ fps.ingested = mtctx->consumed + mtctx->inBuff.filled;
+ fps.consumed = mtctx->consumed;
+ fps.produced = fps.flushed = mtctx->produced;
+ fps.currentJobID = mtctx->nextJobID;
+ fps.nbActiveWorkers = 0;
+ { unsigned jobNb;
+ unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
+ DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
+ mtctx->doneJobID, lastJobNb, mtctx->jobReady)
+ for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
+ unsigned const wJobID = jobNb & mtctx->jobIDMask;
+ ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID];
+ ZSTD_pthread_mutex_lock(&jobPtr->job_mutex);
+ { size_t const cResult = jobPtr->cSize;
+ size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
+ size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed;
+ assert(flushed <= produced);
+ fps.ingested += jobPtr->src.size;
+ fps.consumed += jobPtr->consumed;
+ fps.produced += produced;
+ fps.flushed += flushed;
+ fps.nbActiveWorkers += (jobPtr->consumed < jobPtr->src.size);
+ }
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+ }
+ }
+ return fps;
+}
+
+
+size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx)
+{
+ size_t toFlush;
+ unsigned const jobID = mtctx->doneJobID;
+ assert(jobID <= mtctx->nextJobID);
+ if (jobID == mtctx->nextJobID) return 0; /* no active job => nothing to flush */
+
+ /* look into oldest non-fully-flushed job */
+ { unsigned const wJobID = jobID & mtctx->jobIDMask;
+ ZSTDMT_jobDescription* const jobPtr = &mtctx->jobs[wJobID];
+ ZSTD_pthread_mutex_lock(&jobPtr->job_mutex);
+ { size_t const cResult = jobPtr->cSize;
+ size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
+ size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed;
+ assert(flushed <= produced);
+ toFlush = produced - flushed;
+ if (toFlush==0 && (jobPtr->consumed >= jobPtr->src.size)) {
+ /* doneJobID is not-fully-flushed, but toFlush==0 : doneJobID should be compressing some more data */
+ assert(jobPtr->consumed < jobPtr->src.size);
+ }
+ }
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+ }
+
+ return toFlush;
+}
+
+
+/* ------------------------------------------ */
+/* ===== Multi-threaded compression ===== */
+/* ------------------------------------------ */
+
+static unsigned ZSTDMT_computeTargetJobLog(ZSTD_CCtx_params const params)
+{
+ if (params.ldmParams.enableLdm)
+ /* In Long Range Mode, the windowLog is typically oversized.
+ * In which case, it's preferable to determine the jobSize
+ * based on chainLog instead. */
+ return MAX(21, params.cParams.chainLog + 4);
+ return MAX(20, params.cParams.windowLog + 2);
+}
+
+static int ZSTDMT_overlapLog_default(ZSTD_strategy strat)
+{
+ switch(strat)
+ {
+ case ZSTD_btultra2:
+ return 9;
+ case ZSTD_btultra:
+ case ZSTD_btopt:
+ return 8;
+ case ZSTD_btlazy2:
+ case ZSTD_lazy2:
+ return 7;
+ case ZSTD_lazy:
+ case ZSTD_greedy:
+ case ZSTD_dfast:
+ case ZSTD_fast:
+ default:;
+ }
+ return 6;
+}
+
+static int ZSTDMT_overlapLog(int ovlog, ZSTD_strategy strat)
+{
+ assert(0 <= ovlog && ovlog <= 9);
+ if (ovlog == 0) return ZSTDMT_overlapLog_default(strat);
+ return ovlog;
+}
+
+static size_t ZSTDMT_computeOverlapSize(ZSTD_CCtx_params const params)
+{
+ int const overlapRLog = 9 - ZSTDMT_overlapLog(params.overlapLog, params.cParams.strategy);
+ int ovLog = (overlapRLog >= 8) ? 0 : (params.cParams.windowLog - overlapRLog);
+ assert(0 <= overlapRLog && overlapRLog <= 8);
+ if (params.ldmParams.enableLdm) {
+ /* In Long Range Mode, the windowLog is typically oversized.
+ * In which case, it's preferable to determine the jobSize
+ * based on chainLog instead.
+ * Then, ovLog becomes a fraction of the jobSize, rather than windowSize */
+ ovLog = MIN(params.cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2)
+ - overlapRLog;
+ }
+ assert(0 <= ovLog && ovLog <= 30);
+ DEBUGLOG(4, "overlapLog : %i", params.overlapLog);
+ DEBUGLOG(4, "overlap size : %i", 1 << ovLog);
+ return (ovLog==0) ? 0 : (size_t)1 << ovLog;
+}
+
+static unsigned
+ZSTDMT_computeNbJobs(ZSTD_CCtx_params params, size_t srcSize, unsigned nbWorkers)
+{
+ assert(nbWorkers>0);
+ { size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params);
+ size_t const jobMaxSize = jobSizeTarget << 2;
+ size_t const passSizeMax = jobMaxSize * nbWorkers;
+ unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
+ unsigned const nbJobsLarge = multiplier * nbWorkers;
+ unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1;
+ unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers);
+ return (multiplier>1) ? nbJobsLarge : nbJobsSmall;
+} }
+
+/* ZSTDMT_compress_advanced_internal() :
+ * This is a blocking function : it will only give back control to caller after finishing its compression job.
+ */
+static size_t ZSTDMT_compress_advanced_internal(
+ ZSTDMT_CCtx* mtctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params)
+{
+ ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(params);
+ size_t const overlapSize = ZSTDMT_computeOverlapSize(params);
+ unsigned const nbJobs = ZSTDMT_computeNbJobs(params, srcSize, params.nbWorkers);
+ size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs;
+ size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize; /* avoid too small last block */
+ const char* const srcStart = (const char*)src;
+ size_t remainingSrcSize = srcSize;
+ unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize)); /* presumes avgJobSize >= 256 KB, which should be the case */
+ size_t frameStartPos = 0, dstBufferPos = 0;
+ assert(jobParams.nbWorkers == 0);
+ assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
+
+ params.jobSize = (U32)avgJobSize;
+ DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ",
+ nbJobs, (U32)proposedJobSize, (U32)avgJobSize);
+
+ if ((nbJobs==1) | (params.nbWorkers<=1)) { /* fallback to single-thread mode : this is a blocking invocation anyway */
+ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
+ DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode");
+ if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
+ return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, jobParams);
+ }
+
+ assert(avgJobSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */
+ ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) );
+ if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize))
+ return ERROR(memory_allocation);
+
+ CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbJobs) ); /* only expands if necessary */
+
+ { unsigned u;
+ for (u=0; u<nbJobs; u++) {
+ size_t const jobSize = MIN(remainingSrcSize, avgJobSize);
+ size_t const dstBufferCapacity = ZSTD_compressBound(jobSize);
+ buffer_t const dstAsBuffer = { (char*)dst + dstBufferPos, dstBufferCapacity };
+ buffer_t const dstBuffer = u < compressWithinDst ? dstAsBuffer : g_nullBuffer;
+ size_t dictSize = u ? overlapSize : 0;
+
+ mtctx->jobs[u].prefix.start = srcStart + frameStartPos - dictSize;
+ mtctx->jobs[u].prefix.size = dictSize;
+ mtctx->jobs[u].src.start = srcStart + frameStartPos;
+ mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0); /* avoid job.src.size == 0 */
+ mtctx->jobs[u].consumed = 0;
+ mtctx->jobs[u].cSize = 0;
+ mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
+ mtctx->jobs[u].fullFrameSize = srcSize;
+ mtctx->jobs[u].params = jobParams;
+ /* do not calculate checksum within sections, but write it in header for first section */
+ mtctx->jobs[u].dstBuff = dstBuffer;
+ mtctx->jobs[u].cctxPool = mtctx->cctxPool;
+ mtctx->jobs[u].bufPool = mtctx->bufPool;
+ mtctx->jobs[u].seqPool = mtctx->seqPool;
+ mtctx->jobs[u].serial = &mtctx->serial;
+ mtctx->jobs[u].jobID = u;
+ mtctx->jobs[u].firstJob = (u==0);
+ mtctx->jobs[u].lastJob = (u==nbJobs-1);
+
+ DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)jobSize);
+ DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12);
+ POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]);
+
+ frameStartPos += jobSize;
+ dstBufferPos += dstBufferCapacity;
+ remainingSrcSize -= jobSize;
+ } }
+
+ /* collect result */
+ { size_t error = 0, dstPos = 0;
+ unsigned jobID;
+ for (jobID=0; jobID<nbJobs; jobID++) {
+ DEBUGLOG(5, "waiting for job %u ", jobID);
+ ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
+ while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
+ DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID);
+ ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
+ }
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
+ DEBUGLOG(5, "ready to write job %u ", jobID);
+
+ { size_t const cSize = mtctx->jobs[jobID].cSize;
+ if (ZSTD_isError(cSize)) error = cSize;
+ if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall);
+ if (jobID) { /* note : job 0 is written directly at dst, which is correct position */
+ if (!error)
+ memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize); /* may overlap when job compressed within dst */
+ if (jobID >= compressWithinDst) { /* job compressed into its own buffer, which must be released */
+ DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst);
+ ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
+ } }
+ mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+ mtctx->jobs[jobID].cSize = 0;
+ dstPos += cSize ;
+ }
+ } /* for (jobID=0; jobID<nbJobs; jobID++) */
+
+ DEBUGLOG(4, "checksumFlag : %u ", params.fParams.checksumFlag);
+ if (params.fParams.checksumFlag) {
+ U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
+ if (dstPos + 4 > dstCapacity) {
+ error = ERROR(dstSize_tooSmall);
+ } else {
+ DEBUGLOG(4, "writing checksum : %08X \n", checksum);
+ MEM_writeLE32((char*)dst + dstPos, checksum);
+ dstPos += 4;
+ } }
+
+ if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos);
+ return error ? error : dstPos;
+ }
+}
+
+size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict,
+ ZSTD_parameters params,
+ int overlapLog)
+{
+ ZSTD_CCtx_params cctxParams = mtctx->params;
+ cctxParams.cParams = params.cParams;
+ cctxParams.fParams = params.fParams;
+ assert(ZSTD_OVERLAPLOG_MIN <= overlapLog && overlapLog <= ZSTD_OVERLAPLOG_MAX);
+ cctxParams.overlapLog = overlapLog;
+ return ZSTDMT_compress_advanced_internal(mtctx,
+ dst, dstCapacity,
+ src, srcSize,
+ cdict, cctxParams);
+}
+
+
+size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel)
+{
+ ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0);
+ int const overlapLog = ZSTDMT_overlapLog_default(params.cParams.strategy);
+ params.fParams.contentSizeFlag = 1;
+ return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapLog);
+}
+
+
+/* ====================================== */
+/* ======= Streaming API ======= */
+/* ====================================== */
+
+size_t ZSTDMT_initCStream_internal(
+ ZSTDMT_CCtx* mtctx,
+ const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
+ const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u)",
+ (U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx);
+
+ /* params supposed partially fully validated at this point */
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+
+ /* init */
+ if (params.nbWorkers != mtctx->params.nbWorkers)
+ CHECK_F( ZSTDMT_resize(mtctx, params.nbWorkers) );
+
+ if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN;
+ if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = ZSTDMT_JOBSIZE_MAX;
+
+ mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
+ if (mtctx->singleBlockingThread) {
+ ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
+ DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode");
+ assert(singleThreadParams.nbWorkers == 0);
+ return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0],
+ dict, dictSize, cdict,
+ singleThreadParams, pledgedSrcSize);
+ }
+
+ DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers);
+
+ if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */
+ ZSTDMT_waitForAllJobsCompleted(mtctx);
+ ZSTDMT_releaseAllJobResources(mtctx);
+ mtctx->allJobsCompleted = 1;
+ }
+
+ mtctx->params = params;
+ mtctx->frameContentSize = pledgedSrcSize;
+ if (dict) {
+ ZSTD_freeCDict(mtctx->cdictLocal);
+ mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */
+ params.cParams, mtctx->cMem);
+ mtctx->cdict = mtctx->cdictLocal;
+ if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation);
+ } else {
+ ZSTD_freeCDict(mtctx->cdictLocal);
+ mtctx->cdictLocal = NULL;
+ mtctx->cdict = cdict;
+ }
+
+ mtctx->targetPrefixSize = ZSTDMT_computeOverlapSize(params);
+ DEBUGLOG(4, "overlapLog=%i => %u KB", params.overlapLog, (U32)(mtctx->targetPrefixSize>>10));
+ mtctx->targetSectionSize = params.jobSize;
+ if (mtctx->targetSectionSize == 0) {
+ mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(params);
+ }
+ if (params.rsyncable) {
+ /* Aim for the targetsectionSize as the average job size. */
+ U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20);
+ U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20;
+ assert(jobSizeMB >= 1);
+ DEBUGLOG(4, "rsyncLog = %u", rsyncBits);
+ mtctx->rsync.hash = 0;
+ mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1;
+ mtctx->rsync.primePower = ZSTD_rollingHash_primePower(RSYNC_LENGTH);
+ }
+ if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize; /* job size must be >= overlap size */
+ DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), (U32)params.jobSize);
+ DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10));
+ ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize));
+ {
+ /* If ldm is enabled we need windowSize space. */
+ size_t const windowSize = mtctx->params.ldmParams.enableLdm ? (1U << mtctx->params.cParams.windowLog) : 0;
+ /* Two buffers of slack, plus extra space for the overlap
+ * This is the minimum slack that LDM works with. One extra because
+ * flush might waste up to targetSectionSize-1 bytes. Another extra
+ * for the overlap (if > 0), then one to fill which doesn't overlap
+ * with the LDM window.
+ */
+ size_t const nbSlackBuffers = 2 + (mtctx->targetPrefixSize > 0);
+ size_t const slackSize = mtctx->targetSectionSize * nbSlackBuffers;
+ /* Compute the total size, and always have enough slack */
+ size_t const nbWorkers = MAX(mtctx->params.nbWorkers, 1);
+ size_t const sectionsSize = mtctx->targetSectionSize * nbWorkers;
+ size_t const capacity = MAX(windowSize, sectionsSize) + slackSize;
+ if (mtctx->roundBuff.capacity < capacity) {
+ if (mtctx->roundBuff.buffer)
+ ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
+ mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem);
+ if (mtctx->roundBuff.buffer == NULL) {
+ mtctx->roundBuff.capacity = 0;
+ return ERROR(memory_allocation);
+ }
+ mtctx->roundBuff.capacity = capacity;
+ }
+ }
+ DEBUGLOG(4, "roundBuff capacity : %u KB", (U32)(mtctx->roundBuff.capacity>>10));
+ mtctx->roundBuff.pos = 0;
+ mtctx->inBuff.buffer = g_nullBuffer;
+ mtctx->inBuff.filled = 0;
+ mtctx->inBuff.prefix = kNullRange;
+ mtctx->doneJobID = 0;
+ mtctx->nextJobID = 0;
+ mtctx->frameEnded = 0;
+ mtctx->allJobsCompleted = 0;
+ mtctx->consumed = 0;
+ mtctx->produced = 0;
+ if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize))
+ return ERROR(memory_allocation);
+ return 0;
+}
+
+size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params,
+ unsigned long long pledgedSrcSize)
+{
+ ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */
+ DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
+ cctxParams.cParams = params.cParams;
+ cctxParams.fParams = params.fParams;
+ return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL,
+ cctxParams, pledgedSrcSize);
+}
+
+size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_frameParameters fParams,
+ unsigned long long pledgedSrcSize)
+{
+ ZSTD_CCtx_params cctxParams = mtctx->params;
+ if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */
+ cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
+ cctxParams.fParams = fParams;
+ return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict,
+ cctxParams, pledgedSrcSize);
+}
+
+
+/* ZSTDMT_resetCStream() :
+ * pledgedSrcSize can be zero == unknown (for the time being)
+ * prefer using ZSTD_CONTENTSIZE_UNKNOWN,
+ * as `0` might mean "empty" in the future */
+size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize)
+{
+ if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params,
+ pledgedSrcSize);
+}
+
+size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel) {
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+ ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */
+ DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
+ cctxParams.cParams = params.cParams;
+ cctxParams.fParams = params.fParams;
+ return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+
+/* ZSTDMT_writeLastEmptyBlock()
+ * Write a single empty block with an end-of-frame to finish a frame.
+ * Job must be created from streaming variant.
+ * This function is always successfull if expected conditions are fulfilled.
+ */
+static void ZSTDMT_writeLastEmptyBlock(ZSTDMT_jobDescription* job)
+{
+ assert(job->lastJob == 1);
+ assert(job->src.size == 0); /* last job is empty -> will be simplified into a last empty block */
+ assert(job->firstJob == 0); /* cannot be first job, as it also needs to create frame header */
+ assert(job->dstBuff.start == NULL); /* invoked from streaming variant only (otherwise, dstBuff might be user's output) */
+ job->dstBuff = ZSTDMT_getBuffer(job->bufPool);
+ if (job->dstBuff.start == NULL) {
+ job->cSize = ERROR(memory_allocation);
+ return;
+ }
+ assert(job->dstBuff.capacity >= ZSTD_blockHeaderSize); /* no buffer should ever be that small */
+ job->src = kNullRange;
+ job->cSize = ZSTD_writeLastEmptyBlock(job->dstBuff.start, job->dstBuff.capacity);
+ assert(!ZSTD_isError(job->cSize));
+ assert(job->consumed == 0);
+}
+
+static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* mtctx, size_t srcSize, ZSTD_EndDirective endOp)
+{
+ unsigned const jobID = mtctx->nextJobID & mtctx->jobIDMask;
+ int const endFrame = (endOp == ZSTD_e_end);
+
+ if (mtctx->nextJobID > mtctx->doneJobID + mtctx->jobIDMask) {
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: will not create new job : table is full");
+ assert((mtctx->nextJobID & mtctx->jobIDMask) == (mtctx->doneJobID & mtctx->jobIDMask));
+ return 0;
+ }
+
+ if (!mtctx->jobReady) {
+ BYTE const* src = (BYTE const*)mtctx->inBuff.buffer.start;
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
+ mtctx->nextJobID, (U32)srcSize, (U32)mtctx->inBuff.prefix.size);
+ mtctx->jobs[jobID].src.start = src;
+ mtctx->jobs[jobID].src.size = srcSize;
+ assert(mtctx->inBuff.filled >= srcSize);
+ mtctx->jobs[jobID].prefix = mtctx->inBuff.prefix;
+ mtctx->jobs[jobID].consumed = 0;
+ mtctx->jobs[jobID].cSize = 0;
+ mtctx->jobs[jobID].params = mtctx->params;
+ mtctx->jobs[jobID].cdict = mtctx->nextJobID==0 ? mtctx->cdict : NULL;
+ mtctx->jobs[jobID].fullFrameSize = mtctx->frameContentSize;
+ mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+ mtctx->jobs[jobID].cctxPool = mtctx->cctxPool;
+ mtctx->jobs[jobID].bufPool = mtctx->bufPool;
+ mtctx->jobs[jobID].seqPool = mtctx->seqPool;
+ mtctx->jobs[jobID].serial = &mtctx->serial;
+ mtctx->jobs[jobID].jobID = mtctx->nextJobID;
+ mtctx->jobs[jobID].firstJob = (mtctx->nextJobID==0);
+ mtctx->jobs[jobID].lastJob = endFrame;
+ mtctx->jobs[jobID].frameChecksumNeeded = mtctx->params.fParams.checksumFlag && endFrame && (mtctx->nextJobID>0);
+ mtctx->jobs[jobID].dstFlushed = 0;
+
+ /* Update the round buffer pos and clear the input buffer to be reset */
+ mtctx->roundBuff.pos += srcSize;
+ mtctx->inBuff.buffer = g_nullBuffer;
+ mtctx->inBuff.filled = 0;
+ /* Set the prefix */
+ if (!endFrame) {
+ size_t const newPrefixSize = MIN(srcSize, mtctx->targetPrefixSize);
+ mtctx->inBuff.prefix.start = src + srcSize - newPrefixSize;
+ mtctx->inBuff.prefix.size = newPrefixSize;
+ } else { /* endFrame==1 => no need for another input buffer */
+ mtctx->inBuff.prefix = kNullRange;
+ mtctx->frameEnded = endFrame;
+ if (mtctx->nextJobID == 0) {
+ /* single job exception : checksum is already calculated directly within worker thread */
+ mtctx->params.fParams.checksumFlag = 0;
+ } }
+
+ if ( (srcSize == 0)
+ && (mtctx->nextJobID>0)/*single job must also write frame header*/ ) {
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: creating a last empty block to end frame");
+ assert(endOp == ZSTD_e_end); /* only possible case : need to end the frame with an empty last block */
+ ZSTDMT_writeLastEmptyBlock(mtctx->jobs + jobID);
+ mtctx->nextJobID++;
+ return 0;
+ }
+ }
+
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u, jobNb == %u (mod:%u))",
+ mtctx->nextJobID,
+ (U32)mtctx->jobs[jobID].src.size,
+ mtctx->jobs[jobID].lastJob,
+ mtctx->nextJobID,
+ jobID);
+ if (POOL_tryAdd(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[jobID])) {
+ mtctx->nextJobID++;
+ mtctx->jobReady = 0;
+ } else {
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: no worker available for job %u", mtctx->nextJobID);
+ mtctx->jobReady = 1;
+ }
+ return 0;
+}
+
+
+/*! ZSTDMT_flushProduced() :
+ * flush whatever data has been produced but not yet flushed in current job.
+ * move to next job if current one is fully flushed.
+ * `output` : `pos` will be updated with amount of data flushed .
+ * `blockToFlush` : if >0, the function will block and wait if there is no data available to flush .
+ * @return : amount of data remaining within internal buffer, 0 if no more, 1 if unknown but > 0, or an error code */
+static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned blockToFlush, ZSTD_EndDirective end)
+{
+ unsigned const wJobID = mtctx->doneJobID & mtctx->jobIDMask;
+ DEBUGLOG(5, "ZSTDMT_flushProduced (blocking:%u , job %u <= %u)",
+ blockToFlush, mtctx->doneJobID, mtctx->nextJobID);
+ assert(output->size >= output->pos);
+
+ ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
+ if ( blockToFlush
+ && (mtctx->doneJobID < mtctx->nextJobID) ) {
+ assert(mtctx->jobs[wJobID].dstFlushed <= mtctx->jobs[wJobID].cSize);
+ while (mtctx->jobs[wJobID].dstFlushed == mtctx->jobs[wJobID].cSize) { /* nothing to flush */
+ if (mtctx->jobs[wJobID].consumed == mtctx->jobs[wJobID].src.size) {
+ DEBUGLOG(5, "job %u is completely consumed (%u == %u) => don't wait for cond, there will be none",
+ mtctx->doneJobID, (U32)mtctx->jobs[wJobID].consumed, (U32)mtctx->jobs[wJobID].src.size);
+ break;
+ }
+ DEBUGLOG(5, "waiting for something to flush from job %u (currently flushed: %u bytes)",
+ mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
+ ZSTD_pthread_cond_wait(&mtctx->jobs[wJobID].job_cond, &mtctx->jobs[wJobID].job_mutex); /* block when nothing to flush but some to come */
+ } }
+
+ /* try to flush something */
+ { size_t cSize = mtctx->jobs[wJobID].cSize; /* shared */
+ size_t const srcConsumed = mtctx->jobs[wJobID].consumed; /* shared */
+ size_t const srcSize = mtctx->jobs[wJobID].src.size; /* read-only, could be done after mutex lock, but no-declaration-after-statement */
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+ if (ZSTD_isError(cSize)) {
+ DEBUGLOG(5, "ZSTDMT_flushProduced: job %u : compression error detected : %s",
+ mtctx->doneJobID, ZSTD_getErrorName(cSize));
+ ZSTDMT_waitForAllJobsCompleted(mtctx);
+ ZSTDMT_releaseAllJobResources(mtctx);
+ return cSize;
+ }
+ /* add frame checksum if necessary (can only happen once) */
+ assert(srcConsumed <= srcSize);
+ if ( (srcConsumed == srcSize) /* job completed -> worker no longer active */
+ && mtctx->jobs[wJobID].frameChecksumNeeded ) {
+ U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
+ DEBUGLOG(4, "ZSTDMT_flushProduced: writing checksum : %08X \n", checksum);
+ MEM_writeLE32((char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].cSize, checksum);
+ cSize += 4;
+ mtctx->jobs[wJobID].cSize += 4; /* can write this shared value, as worker is no longer active */
+ mtctx->jobs[wJobID].frameChecksumNeeded = 0;
+ }
+
+ if (cSize > 0) { /* compression is ongoing or completed */
+ size_t const toFlush = MIN(cSize - mtctx->jobs[wJobID].dstFlushed, output->size - output->pos);
+ DEBUGLOG(5, "ZSTDMT_flushProduced: Flushing %u bytes from job %u (completion:%u/%u, generated:%u)",
+ (U32)toFlush, mtctx->doneJobID, (U32)srcConsumed, (U32)srcSize, (U32)cSize);
+ assert(mtctx->doneJobID < mtctx->nextJobID);
+ assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
+ assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
+ memcpy((char*)output->dst + output->pos,
+ (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
+ toFlush);
+ output->pos += toFlush;
+ mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */
+
+ if ( (srcConsumed == srcSize) /* job is completed */
+ && (mtctx->jobs[wJobID].dstFlushed == cSize) ) { /* output buffer fully flushed => free this job position */
+ DEBUGLOG(5, "Job %u completed (%u bytes), moving to next one",
+ mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
+ ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[wJobID].dstBuff);
+ DEBUGLOG(5, "dstBuffer released");
+ mtctx->jobs[wJobID].dstBuff = g_nullBuffer;
+ mtctx->jobs[wJobID].cSize = 0; /* ensure this job slot is considered "not started" in future check */
+ mtctx->consumed += srcSize;
+ mtctx->produced += cSize;
+ mtctx->doneJobID++;
+ } }
+
+ /* return value : how many bytes left in buffer ; fake it to 1 when unknown but >0 */
+ if (cSize > mtctx->jobs[wJobID].dstFlushed) return (cSize - mtctx->jobs[wJobID].dstFlushed);
+ if (srcSize > srcConsumed) return 1; /* current job not completely compressed */
+ }
+ if (mtctx->doneJobID < mtctx->nextJobID) return 1; /* some more jobs ongoing */
+ if (mtctx->jobReady) return 1; /* one job is ready to push, just not yet in the list */
+ if (mtctx->inBuff.filled > 0) return 1; /* input is not empty, and still needs to be converted into a job */
+ mtctx->allJobsCompleted = mtctx->frameEnded; /* all jobs are entirely flushed => if this one is last one, frame is completed */
+ if (end == ZSTD_e_end) return !mtctx->frameEnded; /* for ZSTD_e_end, question becomes : is frame completed ? instead of : are internal buffers fully flushed ? */
+ return 0; /* internal buffers fully flushed */
+}
+
+/**
+ * Returns the range of data used by the earliest job that is not yet complete.
+ * If the data of the first job is broken up into two segments, we cover both
+ * sections.
+ */
+static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx)
+{
+ unsigned const firstJobID = mtctx->doneJobID;
+ unsigned const lastJobID = mtctx->nextJobID;
+ unsigned jobID;
+
+ for (jobID = firstJobID; jobID < lastJobID; ++jobID) {
+ unsigned const wJobID = jobID & mtctx->jobIDMask;
+ size_t consumed;
+
+ ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
+ consumed = mtctx->jobs[wJobID].consumed;
+ ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+
+ if (consumed < mtctx->jobs[wJobID].src.size) {
+ range_t range = mtctx->jobs[wJobID].prefix;
+ if (range.size == 0) {
+ /* Empty prefix */
+ range = mtctx->jobs[wJobID].src;
+ }
+ /* Job source in multiple segments not supported yet */
+ assert(range.start <= mtctx->jobs[wJobID].src.start);
+ return range;
+ }
+ }
+ return kNullRange;
+}
+
+/**
+ * Returns non-zero iff buffer and range overlap.
+ */
+static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range)
+{
+ BYTE const* const bufferStart = (BYTE const*)buffer.start;
+ BYTE const* const bufferEnd = bufferStart + buffer.capacity;
+ BYTE const* const rangeStart = (BYTE const*)range.start;
+ BYTE const* const rangeEnd = rangeStart + range.size;
+
+ if (rangeStart == NULL || bufferStart == NULL)
+ return 0;
+ /* Empty ranges cannot overlap */
+ if (bufferStart == bufferEnd || rangeStart == rangeEnd)
+ return 0;
+
+ return bufferStart < rangeEnd && rangeStart < bufferEnd;
+}
+
+static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window)
+{
+ range_t extDict;
+ range_t prefix;
+
+ DEBUGLOG(5, "ZSTDMT_doesOverlapWindow");
+ extDict.start = window.dictBase + window.lowLimit;
+ extDict.size = window.dictLimit - window.lowLimit;
+
+ prefix.start = window.base + window.dictLimit;
+ prefix.size = window.nextSrc - (window.base + window.dictLimit);
+ DEBUGLOG(5, "extDict [0x%zx, 0x%zx)",
+ (size_t)extDict.start,
+ (size_t)extDict.start + extDict.size);
+ DEBUGLOG(5, "prefix [0x%zx, 0x%zx)",
+ (size_t)prefix.start,
+ (size_t)prefix.start + prefix.size);
+
+ return ZSTDMT_isOverlapped(buffer, extDict)
+ || ZSTDMT_isOverlapped(buffer, prefix);
+}
+
+static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer)
+{
+ if (mtctx->params.ldmParams.enableLdm) {
+ ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex;
+ DEBUGLOG(5, "ZSTDMT_waitForLdmComplete");
+ DEBUGLOG(5, "source [0x%zx, 0x%zx)",
+ (size_t)buffer.start,
+ (size_t)buffer.start + buffer.capacity);
+ ZSTD_PTHREAD_MUTEX_LOCK(mutex);
+ while (ZSTDMT_doesOverlapWindow(buffer, mtctx->serial.ldmWindow)) {
+ DEBUGLOG(5, "Waiting for LDM to finish...");
+ ZSTD_pthread_cond_wait(&mtctx->serial.ldmWindowCond, mutex);
+ }
+ DEBUGLOG(6, "Done waiting for LDM to finish");
+ ZSTD_pthread_mutex_unlock(mutex);
+ }
+}
+
+/**
+ * Attempts to set the inBuff to the next section to fill.
+ * If any part of the new section is still in use we give up.
+ * Returns non-zero if the buffer is filled.
+ */
+static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx)
+{
+ range_t const inUse = ZSTDMT_getInputDataInUse(mtctx);
+ size_t const spaceLeft = mtctx->roundBuff.capacity - mtctx->roundBuff.pos;
+ size_t const target = mtctx->targetSectionSize;
+ buffer_t buffer;
+
+ DEBUGLOG(5, "ZSTDMT_tryGetInputRange");
+ assert(mtctx->inBuff.buffer.start == NULL);
+ assert(mtctx->roundBuff.capacity >= target);
+
+ if (spaceLeft < target) {
+ /* ZSTD_invalidateRepCodes() doesn't work for extDict variants.
+ * Simply copy the prefix to the beginning in that case.
+ */
+ BYTE* const start = (BYTE*)mtctx->roundBuff.buffer;
+ size_t const prefixSize = mtctx->inBuff.prefix.size;
+
+ buffer.start = start;
+ buffer.capacity = prefixSize;
+ if (ZSTDMT_isOverlapped(buffer, inUse)) {
+ DEBUGLOG(5, "Waiting for buffer...");
+ return 0;
+ }
+ ZSTDMT_waitForLdmComplete(mtctx, buffer);
+ memmove(start, mtctx->inBuff.prefix.start, prefixSize);
+ mtctx->inBuff.prefix.start = start;
+ mtctx->roundBuff.pos = prefixSize;
+ }
+ buffer.start = mtctx->roundBuff.buffer + mtctx->roundBuff.pos;
+ buffer.capacity = target;
+
+ if (ZSTDMT_isOverlapped(buffer, inUse)) {
+ DEBUGLOG(5, "Waiting for buffer...");
+ return 0;
+ }
+ assert(!ZSTDMT_isOverlapped(buffer, mtctx->inBuff.prefix));
+
+ ZSTDMT_waitForLdmComplete(mtctx, buffer);
+
+ DEBUGLOG(5, "Using prefix range [%zx, %zx)",
+ (size_t)mtctx->inBuff.prefix.start,
+ (size_t)mtctx->inBuff.prefix.start + mtctx->inBuff.prefix.size);
+ DEBUGLOG(5, "Using source range [%zx, %zx)",
+ (size_t)buffer.start,
+ (size_t)buffer.start + buffer.capacity);
+
+
+ mtctx->inBuff.buffer = buffer;
+ mtctx->inBuff.filled = 0;
+ assert(mtctx->roundBuff.pos + buffer.capacity <= mtctx->roundBuff.capacity);
+ return 1;
+}
+
+typedef struct {
+ size_t toLoad; /* The number of bytes to load from the input. */
+ int flush; /* Boolean declaring if we must flush because we found a synchronization point. */
+} syncPoint_t;
+
+/**
+ * Searches through the input for a synchronization point. If one is found, we
+ * will instruct the caller to flush, and return the number of bytes to load.
+ * Otherwise, we will load as many bytes as possible and instruct the caller
+ * to continue as normal.
+ */
+static syncPoint_t
+findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input)
+{
+ BYTE const* const istart = (BYTE const*)input.src + input.pos;
+ U64 const primePower = mtctx->rsync.primePower;
+ U64 const hitMask = mtctx->rsync.hitMask;
+
+ syncPoint_t syncPoint;
+ U64 hash;
+ BYTE const* prev;
+ size_t pos;
+
+ syncPoint.toLoad = MIN(input.size - input.pos, mtctx->targetSectionSize - mtctx->inBuff.filled);
+ syncPoint.flush = 0;
+ if (!mtctx->params.rsyncable)
+ /* Rsync is disabled. */
+ return syncPoint;
+ if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH)
+ /* Not enough to compute the hash.
+ * We will miss any synchronization points in this RSYNC_LENGTH byte
+ * window. However, since it depends only in the internal buffers, if the
+ * state is already synchronized, we will remain synchronized.
+ * Additionally, the probability that we miss a synchronization point is
+ * low: RSYNC_LENGTH / targetSectionSize.
+ */
+ return syncPoint;
+ /* Initialize the loop variables. */
+ if (mtctx->inBuff.filled >= RSYNC_LENGTH) {
+ /* We have enough bytes buffered to initialize the hash.
+ * Start scanning at the beginning of the input.
+ */
+ pos = 0;
+ prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH;
+ hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH);
+ } else {
+ /* We don't have enough bytes buffered to initialize the hash, but
+ * we know we have at least RSYNC_LENGTH bytes total.
+ * Start scanning after the first RSYNC_LENGTH bytes less the bytes
+ * already buffered.
+ */
+ pos = RSYNC_LENGTH - mtctx->inBuff.filled;
+ prev = (BYTE const*)mtctx->inBuff.buffer.start - pos;
+ hash = ZSTD_rollingHash_compute(mtctx->inBuff.buffer.start, mtctx->inBuff.filled);
+ hash = ZSTD_rollingHash_append(hash, istart, pos);
+ }
+ /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll
+ * through the input. If we hit a synchronization point, then cut the
+ * job off, and tell the compressor to flush the job. Otherwise, load
+ * all the bytes and continue as normal.
+ * If we go too long without a synchronization point (targetSectionSize)
+ * then a block will be emitted anyways, but this is okay, since if we
+ * are already synchronized we will remain synchronized.
+ */
+ for (; pos < syncPoint.toLoad; ++pos) {
+ BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH];
+ /* if (pos >= RSYNC_LENGTH) assert(ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); */
+ hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower);
+ if ((hash & hitMask) == hitMask) {
+ syncPoint.toLoad = pos + 1;
+ syncPoint.flush = 1;
+ break;
+ }
+ }
+ return syncPoint;
+}
+
+size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx)
+{
+ size_t hintInSize = mtctx->targetSectionSize - mtctx->inBuff.filled;
+ if (hintInSize==0) hintInSize = mtctx->targetSectionSize;
+ return hintInSize;
+}
+
+/** ZSTDMT_compressStream_generic() :
+ * internal use only - exposed to be invoked from zstd_compress.c
+ * assumption : output and input are valid (pos <= size)
+ * @return : minimum amount of data remaining to flush, 0 if none */
+size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective endOp)
+{
+ unsigned forwardInputProgress = 0;
+ DEBUGLOG(5, "ZSTDMT_compressStream_generic (endOp=%u, srcSize=%u)",
+ (U32)endOp, (U32)(input->size - input->pos));
+ assert(output->pos <= output->size);
+ assert(input->pos <= input->size);
+
+ if (mtctx->singleBlockingThread) { /* delegate to single-thread (synchronous) */
+ return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
+ }
+
+ if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
+ /* current frame being ended. Only flush/end are allowed */
+ return ERROR(stage_wrong);
+ }
+
+ /* single-pass shortcut (note : synchronous-mode) */
+ if ( (!mtctx->params.rsyncable) /* rsyncable mode is disabled */
+ && (mtctx->nextJobID == 0) /* just started */
+ && (mtctx->inBuff.filled == 0) /* nothing buffered */
+ && (!mtctx->jobReady) /* no job already created */
+ && (endOp == ZSTD_e_end) /* end order */
+ && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */
+ size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
+ (char*)output->dst + output->pos, output->size - output->pos,
+ (const char*)input->src + input->pos, input->size - input->pos,
+ mtctx->cdict, mtctx->params);
+ if (ZSTD_isError(cSize)) return cSize;
+ input->pos = input->size;
+ output->pos += cSize;
+ mtctx->allJobsCompleted = 1;
+ mtctx->frameEnded = 1;
+ return 0;
+ }
+
+ /* fill input buffer */
+ if ( (!mtctx->jobReady)
+ && (input->size > input->pos) ) { /* support NULL input */
+ if (mtctx->inBuff.buffer.start == NULL) {
+ assert(mtctx->inBuff.filled == 0); /* Can't fill an empty buffer */
+ if (!ZSTDMT_tryGetInputRange(mtctx)) {
+ /* It is only possible for this operation to fail if there are
+ * still compression jobs ongoing.
+ */
+ DEBUGLOG(5, "ZSTDMT_tryGetInputRange failed");
+ assert(mtctx->doneJobID != mtctx->nextJobID);
+ } else
+ DEBUGLOG(5, "ZSTDMT_tryGetInputRange completed successfully : mtctx->inBuff.buffer.start = %p", mtctx->inBuff.buffer.start);
+ }
+ if (mtctx->inBuff.buffer.start != NULL) {
+ syncPoint_t const syncPoint = findSynchronizationPoint(mtctx, *input);
+ if (syncPoint.flush && endOp == ZSTD_e_continue) {
+ endOp = ZSTD_e_flush;
+ }
+ assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize);
+ DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u",
+ (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize);
+ memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad);
+ input->pos += syncPoint.toLoad;
+ mtctx->inBuff.filled += syncPoint.toLoad;
+ forwardInputProgress = syncPoint.toLoad>0;
+ }
+ if ((input->pos < input->size) && (endOp == ZSTD_e_end))
+ endOp = ZSTD_e_flush; /* can't end now : not all input consumed */
+ }
+
+ if ( (mtctx->jobReady)
+ || (mtctx->inBuff.filled >= mtctx->targetSectionSize) /* filled enough : let's compress */
+ || ((endOp != ZSTD_e_continue) && (mtctx->inBuff.filled > 0)) /* something to flush : let's go */
+ || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */
+ size_t const jobSize = mtctx->inBuff.filled;
+ assert(mtctx->inBuff.filled <= mtctx->targetSectionSize);
+ CHECK_F( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) );
+ }
+
+ /* check for potential compressed data ready to be flushed */
+ { size_t const remainingToFlush = ZSTDMT_flushProduced(mtctx, output, !forwardInputProgress, endOp); /* block if there was no forward input progress */
+ if (input->pos < input->size) return MAX(remainingToFlush, 1); /* input not consumed : do not end flush yet */
+ DEBUGLOG(5, "end of ZSTDMT_compressStream_generic: remainingToFlush = %u", (U32)remainingToFlush);
+ return remainingToFlush;
+ }
+}
+
+
+size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ CHECK_F( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) );
+
+ /* recommended next input size : fill current input buffer */
+ return mtctx->targetSectionSize - mtctx->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */
+}
+
+
+static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame)
+{
+ size_t const srcSize = mtctx->inBuff.filled;
+ DEBUGLOG(5, "ZSTDMT_flushStream_internal");
+
+ if ( mtctx->jobReady /* one job ready for a worker to pick up */
+ || (srcSize > 0) /* still some data within input buffer */
+ || ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) { /* need a last 0-size block to end frame */
+ DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)",
+ (U32)srcSize, (U32)endFrame);
+ CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
+ }
+
+ /* check if there is any data available to flush */
+ return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame);
+}
+
+
+size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
+{
+ DEBUGLOG(5, "ZSTDMT_flushStream");
+ if (mtctx->singleBlockingThread)
+ return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
+ return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush);
+}
+
+size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
+{
+ DEBUGLOG(4, "ZSTDMT_endStream");
+ if (mtctx->singleBlockingThread)
+ return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
+ return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstdmt_compress.h b/Utilities/cmzstd/lib/compress/zstdmt_compress.h
new file mode 100644
index 000000000..ee771681f
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstdmt_compress.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+ #ifndef ZSTDMT_COMPRESS_H
+ #define ZSTDMT_COMPRESS_H
+
+ #if defined (__cplusplus)
+ extern "C" {
+ #endif
+
+
+/* Note : This is an internal API.
+ * Some methods are still exposed (ZSTDLIB_API),
+ * because it used to be the only way to invoke MT compression.
+ * Now, it's recommended to use ZSTD_compress_generic() instead.
+ * These methods will stop being exposed in a future version */
+
+/* === Dependencies === */
+#include <stddef.h> /* size_t */
+#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */
+#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */
+
+
+/* === Constants === */
+#ifndef ZSTDMT_NBWORKERS_MAX
+# define ZSTDMT_NBWORKERS_MAX 200
+#endif
+#ifndef ZSTDMT_JOBSIZE_MIN
+# define ZSTDMT_JOBSIZE_MIN (1 MB)
+#endif
+#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB))
+
+
+/* === Memory management === */
+typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
+ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers);
+ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
+ ZSTD_customMem cMem);
+ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
+
+ZSTDLIB_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
+
+
+/* === Simple one-pass compression function === */
+
+ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel);
+
+
+
+/* === Streaming functions === */
+
+ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
+ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */
+
+ZSTDLIB_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx);
+ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+
+ZSTDLIB_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
+
+
+/* === Advanced functions and parameters === */
+
+ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict,
+ ZSTD_parameters params,
+ int overlapLog);
+
+ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
+ const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */
+ ZSTD_parameters params,
+ unsigned long long pledgedSrcSize); /* pledgedSrcSize is optional and can be zero == unknown */
+
+ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_frameParameters fparams,
+ unsigned long long pledgedSrcSize); /* note : zero means empty */
+
+/* ZSTDMT_parameter :
+ * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
+typedef enum {
+ ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */
+ ZSTDMT_p_overlapLog, /* Each job may reload a part of previous job to enhance compressionr ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */
+ ZSTDMT_p_rsyncable /* Enables rsyncable mode. */
+} ZSTDMT_parameter;
+
+/* ZSTDMT_setMTCtxParameter() :
+ * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
+ * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__
+ * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value);
+
+/* ZSTDMT_getMTCtxParameter() :
+ * Query the ZSTDMT_CCtx for a parameter value.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value);
+
+
+/*! ZSTDMT_compressStream_generic() :
+ * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
+ * depending on flush directive.
+ * @return : minimum amount of data still to be flushed
+ * 0 if fully flushed
+ * or an error code
+ * note : needs to be init using any ZSTD_initCStream*() variant */
+ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective endOp);
+
+
+/* ========================================================
+ * === Private interface, for use by ZSTD_compress.c ===
+ * === Not exposed in libzstd. Never invoke directly ===
+ * ======================================================== */
+
+ /*! ZSTDMT_toFlushNow()
+ * Tell how many bytes are ready to be flushed immediately.
+ * Probe the oldest active job (not yet entirely flushed) and check its output buffer.
+ * If return 0, it means there is no active job,
+ * or, it means oldest job is still active, but everything produced has been flushed so far,
+ * therefore flushing is limited by speed of oldest job. */
+size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx);
+
+/*! ZSTDMT_CCtxParam_setMTCtxParameter()
+ * like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */
+size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value);
+
+/*! ZSTDMT_CCtxParam_setNbWorkers()
+ * Set nbWorkers, and clamp it.
+ * Also reset jobSize and overlapLog */
+size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers);
+
+/*! ZSTDMT_updateCParams_whileCompressing() :
+ * Updates only a selected set of compression parameters, to remain compatible with current frame.
+ * New parameters will be applied to next compression job. */
+void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams);
+
+/*! ZSTDMT_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads.
+ */
+ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
+
+
+/*! ZSTDMT_initCStream_internal() :
+ * Private use only. Init streaming operation.
+ * expects params to be valid.
+ * must receive dict, or cdict, or none, but not both.
+ * @return : 0, or an error code */
+size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
+ const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTDMT_COMPRESS_H */
diff --git a/Utilities/cmzstd/lib/decompress/huf_decompress.c b/Utilities/cmzstd/lib/decompress/huf_decompress.c
new file mode 100644
index 000000000..3f8bd2973
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/huf_decompress.c
@@ -0,0 +1,1232 @@
+/* ******************************************************************
+ huff0 huffman decoder,
+ part of Finite State Entropy library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ OWNER 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.
+
+ You can contact the author at :
+ - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+/* **************************************************************
+* Dependencies
+****************************************************************/
+#include <string.h> /* memcpy, memset */
+#include "compiler.h"
+#include "bitstream.h" /* BIT_* */
+#include "fse.h" /* to compress headers */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "error_private.h"
+
+/* **************************************************************
+* Macros
+****************************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * Huffman decompression implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(HUF_FORCE_DECOMPRESS_X1) && \
+ defined(HUF_FORCE_DECOMPRESS_X2)
+#error "Cannot force the use of the X1 and X2 decoders at the same time!"
+#endif
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+#define CHECK_F(f) { size_t const err_ = (f); if (HUF_isError(err_)) return err_; }
+
+
+/* **************************************************************
+* Byte alignment for workSpace management
+****************************************************************/
+#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1)
+#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+
+/* **************************************************************
+* BMI2 Variant Wrappers
+****************************************************************/
+#if DYNAMIC_BMI2
+
+#define HUF_DGEN(fn) \
+ \
+ static size_t fn##_default( \
+ void* dst, size_t dstSize, \
+ const void* cSrc, size_t cSrcSize, \
+ const HUF_DTable* DTable) \
+ { \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ \
+ static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \
+ void* dst, size_t dstSize, \
+ const void* cSrc, size_t cSrcSize, \
+ const HUF_DTable* DTable) \
+ { \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ \
+ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
+ size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
+ { \
+ if (bmi2) { \
+ return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \
+ }
+
+#else
+
+#define HUF_DGEN(fn) \
+ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
+ size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
+ { \
+ (void)bmi2; \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ }
+
+#endif
+
+
+/*-***************************/
+/* generic DTableDesc */
+/*-***************************/
+typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
+
+static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
+{
+ DTableDesc dtd;
+ memcpy(&dtd, table, sizeof(dtd));
+ return dtd;
+}
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+
+/*-***************************/
+/* single-symbol decoding */
+/*-***************************/
+typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */
+
+size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
+{
+ U32 tableLog = 0;
+ U32 nbSymbols = 0;
+ size_t iSize;
+ void* const dtPtr = DTable + 1;
+ HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
+
+ U32* rankVal;
+ BYTE* huffWeight;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
+ huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+ DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
+ /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
+
+ iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
+ if (HUF_isError(iSize)) return iSize;
+
+ /* Table header */
+ { DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
+ dtd.tableType = 0;
+ dtd.tableLog = (BYTE)tableLog;
+ memcpy(DTable, &dtd, sizeof(dtd));
+ }
+
+ /* Calculate starting value for each rank */
+ { U32 n, nextRankStart = 0;
+ for (n=1; n<tableLog+1; n++) {
+ U32 const current = nextRankStart;
+ nextRankStart += (rankVal[n] << (n-1));
+ rankVal[n] = current;
+ } }
+
+ /* fill DTable */
+ { U32 n;
+ for (n=0; n<nbSymbols; n++) {
+ U32 const w = huffWeight[n];
+ U32 const length = (1 << w) >> 1;
+ U32 u;
+ HUF_DEltX1 D;
+ D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
+ for (u = rankVal[w]; u < rankVal[w] + length; u++)
+ dt[u] = D;
+ rankVal[w] += length;
+ } }
+
+ return iSize;
+}
+
+size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_readDTableX1_wksp(DTable, src, srcSize,
+ workSpace, sizeof(workSpace));
+}
+
+FORCE_INLINE_TEMPLATE BYTE
+HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
+ BYTE const c = dt[val].byte;
+ BIT_skipBits(Dstream, dt[val].nbBits);
+ return c;
+}
+
+#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
+ *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
+ if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+ HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
+ if (MEM_64bits()) \
+ HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+HINT_INLINE size_t
+HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
+{
+ BYTE* const pStart = p;
+
+ /* up to 4 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
+ HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_1(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+ }
+
+ /* [0-3] symbols remaining */
+ if (MEM_32bits())
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+ /* no more data to retrieve from bitstream, no need to reload */
+ while (p < pEnd)
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+ return pEnd-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X1_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ BYTE* op = (BYTE*)dst;
+ BYTE* const oend = op + dstSize;
+ const void* dtPtr = DTable + 1;
+ const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+ BIT_DStream_t bitD;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+
+ CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+ HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
+
+ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+ return dstSize;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X1_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ /* Check */
+ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+
+ { const BYTE* const istart = (const BYTE*) cSrc;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ const void* const dtPtr = DTable + 1;
+ const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+
+ /* Init */
+ BIT_DStream_t bitD1;
+ BIT_DStream_t bitD2;
+ BIT_DStream_t bitD3;
+ BIT_DStream_t bitD4;
+ size_t const length1 = MEM_readLE16(istart);
+ size_t const length2 = MEM_readLE16(istart+2);
+ size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+ const BYTE* const istart1 = istart + 6; /* jumpTable */
+ const BYTE* const istart2 = istart1 + length1;
+ const BYTE* const istart3 = istart2 + length2;
+ const BYTE* const istart4 = istart3 + length3;
+ const size_t segmentSize = (dstSize+3) / 4;
+ BYTE* const opStart2 = ostart + segmentSize;
+ BYTE* const opStart3 = opStart2 + segmentSize;
+ BYTE* const opStart4 = opStart3 + segmentSize;
+ BYTE* op1 = ostart;
+ BYTE* op2 = opStart2;
+ BYTE* op3 = opStart3;
+ BYTE* op4 = opStart4;
+ U32 endSignal = BIT_DStream_unfinished;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+
+ if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
+ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+ CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+ CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+ CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+ /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
+ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+ while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) {
+ HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_1(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_1(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_1(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_1(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_0(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_0(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_0(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_0(op4, &bitD4);
+ BIT_reloadDStream(&bitD1);
+ BIT_reloadDStream(&bitD2);
+ BIT_reloadDStream(&bitD3);
+ BIT_reloadDStream(&bitD4);
+ }
+
+ /* check corruption */
+ /* note : should not be necessary : op# advance in lock step, and we control op4.
+ * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */
+ if (op1 > opStart2) return ERROR(corruption_detected);
+ if (op2 > opStart3) return ERROR(corruption_detected);
+ if (op3 > opStart4) return ERROR(corruption_detected);
+ /* note : op4 supposed already verified within main loop */
+
+ /* finish bitStreams one by one */
+ HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
+ HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
+ HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
+ HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog);
+
+ /* check */
+ { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+ if (!endCheck) return ERROR(corruption_detected); }
+
+ /* decoded size */
+ return dstSize;
+ }
+}
+
+
+typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
+ const void *cSrc,
+ size_t cSrcSize,
+ const HUF_DTable *DTable);
+
+HUF_DGEN(HUF_decompress1X1_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X1_usingDTable_internal)
+
+
+
+size_t HUF_decompress1X1_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 0) return ERROR(GENERIC);
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X1_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 0) return ERROR(GENERIC);
+ return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
+}
+
+
+size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X2 */
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X1
+
+/* *************************/
+/* double-symbols decoding */
+/* *************************/
+
+typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */
+typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
+typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
+typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
+
+
+/* HUF_fillDTableX2Level2() :
+ * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
+static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
+ const U32* rankValOrigin, const int minWeight,
+ const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
+ U32 nbBitsBaseline, U16 baseSeq)
+{
+ HUF_DEltX2 DElt;
+ U32 rankVal[HUF_TABLELOG_MAX + 1];
+
+ /* get pre-calculated rankVal */
+ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+ /* fill skipped values */
+ if (minWeight>1) {
+ U32 i, skipSize = rankVal[minWeight];
+ MEM_writeLE16(&(DElt.sequence), baseSeq);
+ DElt.nbBits = (BYTE)(consumed);
+ DElt.length = 1;
+ for (i = 0; i < skipSize; i++)
+ DTable[i] = DElt;
+ }
+
+ /* fill DTable */
+ { U32 s; for (s=0; s<sortedListSize; s++) { /* note : sortedSymbols already skipped */
+ const U32 symbol = sortedSymbols[s].symbol;
+ const U32 weight = sortedSymbols[s].weight;
+ const U32 nbBits = nbBitsBaseline - weight;
+ const U32 length = 1 << (sizeLog-nbBits);
+ const U32 start = rankVal[weight];
+ U32 i = start;
+ const U32 end = start + length;
+
+ MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
+ DElt.nbBits = (BYTE)(nbBits + consumed);
+ DElt.length = 2;
+ do { DTable[i++] = DElt; } while (i<end); /* since length >= 1 */
+
+ rankVal[weight] += length;
+ } }
+}
+
+
+static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
+ const sortedSymbol_t* sortedList, const U32 sortedListSize,
+ const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
+ const U32 nbBitsBaseline)
+{
+ U32 rankVal[HUF_TABLELOG_MAX + 1];
+ const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
+ const U32 minBits = nbBitsBaseline - maxWeight;
+ U32 s;
+
+ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+ /* fill DTable */
+ for (s=0; s<sortedListSize; s++) {
+ const U16 symbol = sortedList[s].symbol;
+ const U32 weight = sortedList[s].weight;
+ const U32 nbBits = nbBitsBaseline - weight;
+ const U32 start = rankVal[weight];
+ const U32 length = 1 << (targetLog-nbBits);
+
+ if (targetLog-nbBits >= minBits) { /* enough room for a second symbol */
+ U32 sortedRank;
+ int minWeight = nbBits + scaleLog;
+ if (minWeight < 1) minWeight = 1;
+ sortedRank = rankStart[minWeight];
+ HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
+ rankValOrigin[nbBits], minWeight,
+ sortedList+sortedRank, sortedListSize-sortedRank,
+ nbBitsBaseline, symbol);
+ } else {
+ HUF_DEltX2 DElt;
+ MEM_writeLE16(&(DElt.sequence), symbol);
+ DElt.nbBits = (BYTE)(nbBits);
+ DElt.length = 1;
+ { U32 const end = start + length;
+ U32 u;
+ for (u = start; u < end; u++) DTable[u] = DElt;
+ } }
+ rankVal[weight] += length;
+ }
+}
+
+size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t wkspSize)
+{
+ U32 tableLog, maxW, sizeOfSort, nbSymbols;
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ U32 const maxTableLog = dtd.maxTableLog;
+ size_t iSize;
+ void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
+ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
+ U32 *rankStart;
+
+ rankValCol_t* rankVal;
+ U32* rankStats;
+ U32* rankStart0;
+ sortedSymbol_t* sortedSymbol;
+ BYTE* weightList;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
+ rankStats = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 1;
+ rankStart0 = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 2;
+ sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
+ spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
+ weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+ rankStart = rankStart0 + 1;
+ memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+
+ DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
+ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
+
+ iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
+ if (HUF_isError(iSize)) return iSize;
+
+ /* check result */
+ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
+
+ /* find maxWeight */
+ for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
+
+ /* Get start index of each weight */
+ { U32 w, nextRankStart = 0;
+ for (w=1; w<maxW+1; w++) {
+ U32 current = nextRankStart;
+ nextRankStart += rankStats[w];
+ rankStart[w] = current;
+ }
+ rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
+ sizeOfSort = nextRankStart;
+ }
+
+ /* sort symbols by weight */
+ { U32 s;
+ for (s=0; s<nbSymbols; s++) {
+ U32 const w = weightList[s];
+ U32 const r = rankStart[w]++;
+ sortedSymbol[r].symbol = (BYTE)s;
+ sortedSymbol[r].weight = (BYTE)w;
+ }
+ rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
+ }
+
+ /* Build rankVal */
+ { U32* const rankVal0 = rankVal[0];
+ { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */
+ U32 nextRankVal = 0;
+ U32 w;
+ for (w=1; w<maxW+1; w++) {
+ U32 current = nextRankVal;
+ nextRankVal += rankStats[w] << (w+rescale);
+ rankVal0[w] = current;
+ } }
+ { U32 const minBits = tableLog+1 - maxW;
+ U32 consumed;
+ for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
+ U32* const rankValPtr = rankVal[consumed];
+ U32 w;
+ for (w = 1; w < maxW+1; w++) {
+ rankValPtr[w] = rankVal0[w] >> consumed;
+ } } } }
+
+ HUF_fillDTableX2(dt, maxTableLog,
+ sortedSymbol, sizeOfSort,
+ rankStart0, rankVal, maxW,
+ tableLog+1);
+
+ dtd.tableLog = (BYTE)maxTableLog;
+ dtd.tableType = 1;
+ memcpy(DTable, &dtd, sizeof(dtd));
+ return iSize;
+}
+
+size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_readDTableX2_wksp(DTable, src, srcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt+val, 2);
+ BIT_skipBits(DStream, dt[val].nbBits);
+ return dt[val].length;
+}
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt+val, 1);
+ if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
+ else {
+ if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
+ BIT_skipBits(DStream, dt[val].nbBits);
+ if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
+ /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
+ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
+ } }
+ return 1;
+}
+
+#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
+ if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
+ if (MEM_64bits()) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+HINT_INLINE size_t
+HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
+ const HUF_DEltX2* const dt, const U32 dtLog)
+{
+ BYTE* const pStart = p;
+
+ /* up to 8 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
+ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+ }
+
+ /* closer to end : up to 2 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+
+ while (p <= pEnd-2)
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
+
+ if (p < pEnd)
+ p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
+
+ return p-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X2_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ BIT_DStream_t bitD;
+
+ /* Init */
+ CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+ /* decode */
+ { BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
+ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog);
+ }
+
+ /* check */
+ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+ /* decoded size */
+ return dstSize;
+}
+
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X2_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+
+ { const BYTE* const istart = (const BYTE*) cSrc;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ const void* const dtPtr = DTable+1;
+ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+
+ /* Init */
+ BIT_DStream_t bitD1;
+ BIT_DStream_t bitD2;
+ BIT_DStream_t bitD3;
+ BIT_DStream_t bitD4;
+ size_t const length1 = MEM_readLE16(istart);
+ size_t const length2 = MEM_readLE16(istart+2);
+ size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+ const BYTE* const istart1 = istart + 6; /* jumpTable */
+ const BYTE* const istart2 = istart1 + length1;
+ const BYTE* const istart3 = istart2 + length2;
+ const BYTE* const istart4 = istart3 + length3;
+ size_t const segmentSize = (dstSize+3) / 4;
+ BYTE* const opStart2 = ostart + segmentSize;
+ BYTE* const opStart3 = opStart2 + segmentSize;
+ BYTE* const opStart4 = opStart3 + segmentSize;
+ BYTE* op1 = ostart;
+ BYTE* op2 = opStart2;
+ BYTE* op3 = opStart3;
+ BYTE* op4 = opStart4;
+ U32 endSignal;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+
+ if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
+ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+ CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+ CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+ CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+ /* 16-32 symbols per loop (4-8 symbols per stream) */
+ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+ for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
+
+ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+ }
+
+ /* check corruption */
+ if (op1 > opStart2) return ERROR(corruption_detected);
+ if (op2 > opStart3) return ERROR(corruption_detected);
+ if (op3 > opStart4) return ERROR(corruption_detected);
+ /* note : op4 already verified within main loop */
+
+ /* finish bitStreams one by one */
+ HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
+ HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
+ HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
+ HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
+
+ /* check */
+ { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+ if (!endCheck) return ERROR(corruption_detected); }
+
+ /* decoded size */
+ return dstSize;
+ }
+}
+
+HUF_DGEN(HUF_decompress1X2_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X2_usingDTable_internal)
+
+size_t HUF_decompress1X2_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 1) return ERROR(GENERIC);
+ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X2_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 1) return ERROR(GENERIC);
+ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X1 */
+
+
+/* ***********************************/
+/* Universal decompression selectors */
+/* ***********************************/
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+ return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+ HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+ return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+ HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
+static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
+{
+ /* single, double, quad */
+ {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */
+ {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */
+ {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
+ {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
+ {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
+ {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
+ {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
+ {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
+ {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
+ {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
+ {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
+ {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
+ {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
+ {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */
+ {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */
+ {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */
+};
+#endif
+
+/** HUF_selectDecoder() :
+ * Tells which decoder is likely to decode faster,
+ * based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ * Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
+{
+ assert(dstSize > 0);
+ assert(dstSize <= 128*1024);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dstSize;
+ (void)cSrcSize;
+ return 0;
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dstSize;
+ (void)cSrcSize;
+ return 1;
+#else
+ /* decoder timing evaluation */
+ { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
+ U32 const D256 = (U32)(dstSize >> 8);
+ U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
+ U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
+ DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */
+ return DTime1 < DTime0;
+ }
+#endif
+}
+
+
+typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+
+size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+ static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
+#endif
+
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
+#else
+ return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
+#endif
+ }
+}
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
+ HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+#endif
+ }
+}
+
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
+ size_t dstSize, const void* cSrc,
+ size_t cSrcSize, void* workSpace,
+ size_t wkspSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize == 0) return ERROR(corruption_detected);
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize):
+ HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#endif
+ }
+}
+
+size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#else
+ return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize):
+ HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#endif
+ }
+}
+
+size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+ return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+ HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+#endif
+
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+ return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+ HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize == 0) return ERROR(corruption_detected);
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
+ HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#endif
+ }
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_ddict.c b/Utilities/cmzstd/lib/decompress/zstd_ddict.c
new file mode 100644
index 000000000..2ad044068
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_ddict.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_ddict.c :
+ * concentrates all logic that needs to know the internals of ZSTD_DDict object */
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "cpu.h" /* bmi2 */
+#include "mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_decompress_internal.h"
+#include "zstd_ddict.h"
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+# include "zstd_legacy.h"
+#endif
+
+
+
+/*-*******************************************************
+* Types
+*********************************************************/
+struct ZSTD_DDict_s {
+ void* dictBuffer;
+ const void* dictContent;
+ size_t dictSize;
+ ZSTD_entropyDTables_t entropy;
+ U32 dictID;
+ U32 entropyPresent;
+ ZSTD_customMem cMem;
+}; /* typedef'd to ZSTD_DDict within "zstd.h" */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)
+{
+ assert(ddict != NULL);
+ return ddict->dictContent;
+}
+
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)
+{
+ assert(ddict != NULL);
+ return ddict->dictSize;
+}
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ DEBUGLOG(4, "ZSTD_copyDDictParameters");
+ assert(dctx != NULL);
+ assert(ddict != NULL);
+ dctx->dictID = ddict->dictID;
+ dctx->prefixStart = ddict->dictContent;
+ dctx->virtualStart = ddict->dictContent;
+ dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
+ dctx->previousDstEnd = dctx->dictEnd;
+ if (ddict->entropyPresent) {
+ dctx->litEntropy = 1;
+ dctx->fseEntropy = 1;
+ dctx->LLTptr = ddict->entropy.LLTable;
+ dctx->MLTptr = ddict->entropy.MLTable;
+ dctx->OFTptr = ddict->entropy.OFTable;
+ dctx->HUFptr = ddict->entropy.hufTable;
+ dctx->entropy.rep[0] = ddict->entropy.rep[0];
+ dctx->entropy.rep[1] = ddict->entropy.rep[1];
+ dctx->entropy.rep[2] = ddict->entropy.rep[2];
+ } else {
+ dctx->litEntropy = 0;
+ dctx->fseEntropy = 0;
+ }
+}
+
+
+static size_t
+ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
+ ZSTD_dictContentType_e dictContentType)
+{
+ ddict->dictID = 0;
+ ddict->entropyPresent = 0;
+ if (dictContentType == ZSTD_dct_rawContent) return 0;
+
+ if (ddict->dictSize < 8) {
+ if (dictContentType == ZSTD_dct_fullDict)
+ return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
+ return 0; /* pure content mode */
+ }
+ { U32 const magic = MEM_readLE32(ddict->dictContent);
+ if (magic != ZSTD_MAGIC_DICTIONARY) {
+ if (dictContentType == ZSTD_dct_fullDict)
+ return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
+ return 0; /* pure content mode */
+ }
+ }
+ ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);
+
+ /* load entropy tables */
+ CHECK_E( ZSTD_loadDEntropy(&ddict->entropy,
+ ddict->dictContent, ddict->dictSize),
+ dictionary_corrupted );
+ ddict->entropyPresent = 1;
+ return 0;
+}
+
+
+static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
+ ddict->dictBuffer = NULL;
+ ddict->dictContent = dict;
+ if (!dict) dictSize = 0;
+ } else {
+ void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
+ ddict->dictBuffer = internalBuffer;
+ ddict->dictContent = internalBuffer;
+ if (!internalBuffer) return ERROR(memory_allocation);
+ memcpy(internalBuffer, dict, dictSize);
+ }
+ ddict->dictSize = dictSize;
+ ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+
+ /* parse dictionary content */
+ CHECK_F( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) );
+
+ return 0;
+}
+
+ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_customMem customMem)
+{
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
+ if (ddict == NULL) return NULL;
+ ddict->cMem = customMem;
+ { size_t const initResult = ZSTD_initDDict_internal(ddict,
+ dict, dictSize,
+ dictLoadMethod, dictContentType);
+ if (ZSTD_isError(initResult)) {
+ ZSTD_freeDDict(ddict);
+ return NULL;
+ } }
+ return ddict;
+ }
+}
+
+/*! ZSTD_createDDict() :
+* Create a digested dictionary, to start decompression without startup delay.
+* `dict` content is copied inside DDict.
+* Consequently, `dict` can be released after `ZSTD_DDict` creation */
+ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
+{
+ ZSTD_customMem const allocator = { NULL, NULL, NULL };
+ return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
+}
+
+/*! ZSTD_createDDict_byReference() :
+ * Create a digested dictionary, to start decompression without startup delay.
+ * Dictionary content is simply referenced, it will be accessed during decompression.
+ * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */
+ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
+{
+ ZSTD_customMem const allocator = { NULL, NULL, NULL };
+ return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
+}
+
+
+const ZSTD_DDict* ZSTD_initStaticDDict(
+ void* sBuffer, size_t sBufferSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ size_t const neededSpace = sizeof(ZSTD_DDict)
+ + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+ ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;
+ assert(sBuffer != NULL);
+ assert(dict != NULL);
+ if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */
+ if (sBufferSize < neededSpace) return NULL;
+ if (dictLoadMethod == ZSTD_dlm_byCopy) {
+ memcpy(ddict+1, dict, dictSize); /* local copy */
+ dict = ddict+1;
+ }
+ if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
+ dict, dictSize,
+ ZSTD_dlm_byRef, dictContentType) ))
+ return NULL;
+ return ddict;
+}
+
+
+size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0; /* support free on NULL */
+ { ZSTD_customMem const cMem = ddict->cMem;
+ ZSTD_free(ddict->dictBuffer, cMem);
+ ZSTD_free(ddict, cMem);
+ return 0;
+ }
+}
+
+/*! ZSTD_estimateDDictSize() :
+ * Estimate amount of memory that will be needed to create a dictionary for decompression.
+ * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
+size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+ return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+}
+
+size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0; /* support sizeof on NULL */
+ return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;
+}
+
+/*! ZSTD_getDictID_fromDDict() :
+ * Provides the dictID of the dictionary loaded into `ddict`.
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0;
+ return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_ddict.h b/Utilities/cmzstd/lib/decompress/zstd_ddict.h
new file mode 100644
index 000000000..0479d11bb
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_ddict.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DDICT_H
+#define ZSTD_DDICT_H
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include <stddef.h> /* size_t */
+#include "zstd.h" /* ZSTD_DDict, and several public functions */
+
+
+/*-*******************************************************
+ * Interface
+ *********************************************************/
+
+/* note: several prototypes are already published in `zstd.h` :
+ * ZSTD_createDDict()
+ * ZSTD_createDDict_byReference()
+ * ZSTD_createDDict_advanced()
+ * ZSTD_freeDDict()
+ * ZSTD_initStaticDDict()
+ * ZSTD_sizeof_DDict()
+ * ZSTD_estimateDDictSize()
+ * ZSTD_getDictID_fromDict()
+ */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict);
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict);
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+
+
+#endif /* ZSTD_DDICT_H */
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress.c b/Utilities/cmzstd/lib/decompress/zstd_decompress.c
new file mode 100644
index 000000000..feef1ef67
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress.c
@@ -0,0 +1,1672 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ***************************************************************
+* Tuning parameters
+*****************************************************************/
+/*!
+ * HEAPMODE :
+ * Select how default decompression function ZSTD_decompress() allocates its context,
+ * on stack (0), or into heap (1, default; requires malloc()).
+ * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
+ */
+#ifndef ZSTD_HEAPMODE
+# define ZSTD_HEAPMODE 1
+#endif
+
+/*!
+* LEGACY_SUPPORT :
+* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
+*/
+#ifndef ZSTD_LEGACY_SUPPORT
+# define ZSTD_LEGACY_SUPPORT 0
+#endif
+
+/*!
+ * MAXWINDOWSIZE_DEFAULT :
+ * maximum window size accepted by DStream __by default__.
+ * Frames requiring more memory will be rejected.
+ * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
+ */
+#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
+# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
+#endif
+
+/*!
+ * NO_FORWARD_PROGRESS_MAX :
+ * maximum allowed nb of calls to ZSTD_decompressStream()
+ * without any forward progress
+ * (defined as: no byte read from input, and no byte flushed to output)
+ * before triggering an error.
+ */
+#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
+# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
+#endif
+
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "cpu.h" /* bmi2 */
+#include "mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_internal.h" /* blockProperties_t */
+#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
+#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+# include "zstd_legacy.h"
+#endif
+
+
+/*-*************************************************************
+* Context management
+***************************************************************/
+size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
+{
+ if (dctx==NULL) return 0; /* support sizeof NULL */
+ return sizeof(*dctx)
+ + ZSTD_sizeof_DDict(dctx->ddictLocal)
+ + dctx->inBuffSize + dctx->outBuffSize;
+}
+
+size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
+
+
+static size_t ZSTD_startingInputLength(ZSTD_format_e format)
+{
+ size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
+ ZSTD_FRAMEHEADERSIZE_PREFIX - ZSTD_FRAMEIDSIZE :
+ ZSTD_FRAMEHEADERSIZE_PREFIX;
+ ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
+ /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
+ assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
+ return startingInputLength;
+}
+
+static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
+{
+ dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
+ dctx->staticSize = 0;
+ dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+ dctx->ddict = NULL;
+ dctx->ddictLocal = NULL;
+ dctx->dictEnd = NULL;
+ dctx->ddictIsCold = 0;
+ dctx->inBuff = NULL;
+ dctx->inBuffSize = 0;
+ dctx->outBuffSize = 0;
+ dctx->streamStage = zdss_init;
+ dctx->legacyContext = NULL;
+ dctx->previousLegacyVersion = 0;
+ dctx->noForwardProgress = 0;
+ dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+}
+
+ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
+{
+ ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
+
+ if ((size_t)workspace & 7) return NULL; /* 8-aligned */
+ if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
+
+ ZSTD_initDCtx_internal(dctx);
+ dctx->staticSize = workspaceSize;
+ dctx->inBuff = (char*)(dctx+1);
+ return dctx;
+}
+
+ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
+{
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
+ if (!dctx) return NULL;
+ dctx->customMem = customMem;
+ ZSTD_initDCtx_internal(dctx);
+ return dctx;
+ }
+}
+
+ZSTD_DCtx* ZSTD_createDCtx(void)
+{
+ DEBUGLOG(3, "ZSTD_createDCtx");
+ return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
+{
+ if (dctx==NULL) return 0; /* support free on NULL */
+ if (dctx->staticSize) return ERROR(memory_allocation); /* not compatible with static DCtx */
+ { ZSTD_customMem const cMem = dctx->customMem;
+ ZSTD_freeDDict(dctx->ddictLocal);
+ dctx->ddictLocal = NULL;
+ ZSTD_free(dctx->inBuff, cMem);
+ dctx->inBuff = NULL;
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (dctx->legacyContext)
+ ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
+#endif
+ ZSTD_free(dctx, cMem);
+ return 0;
+ }
+}
+
+/* no longer useful */
+void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
+{
+ size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
+ memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
+}
+
+
+/*-*************************************************************
+ * Frame header decoding
+ ***************************************************************/
+
+/*! ZSTD_isFrame() :
+ * Tells if the content of `buffer` starts with a valid Frame Identifier.
+ * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
+ * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
+ * Note 3 : Skippable Frame Identifiers are considered valid. */
+unsigned ZSTD_isFrame(const void* buffer, size_t size)
+{
+ if (size < ZSTD_FRAMEIDSIZE) return 0;
+ { U32 const magic = MEM_readLE32(buffer);
+ if (magic == ZSTD_MAGICNUMBER) return 1;
+ if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
+ }
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(buffer, size)) return 1;
+#endif
+ return 0;
+}
+
+/** ZSTD_frameHeaderSize_internal() :
+ * srcSize must be large enough to reach header size fields.
+ * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
+ * @return : size of the Frame Header
+ * or an error code, which can be tested with ZSTD_isError() */
+static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
+{
+ size_t const minInputSize = ZSTD_startingInputLength(format);
+ if (srcSize < minInputSize) return ERROR(srcSize_wrong);
+
+ { BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
+ U32 const dictID= fhd & 3;
+ U32 const singleSegment = (fhd >> 5) & 1;
+ U32 const fcsId = fhd >> 6;
+ return minInputSize + !singleSegment
+ + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
+ + (singleSegment && !fcsId);
+ }
+}
+
+/** ZSTD_frameHeaderSize() :
+ * srcSize must be >= ZSTD_frameHeaderSize_prefix.
+ * @return : size of the Frame Header,
+ * or an error code (if srcSize is too small) */
+size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
+{
+ return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameHeader_advanced() :
+ * decode Frame Header, or require larger `srcSize`.
+ * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
+ * @return : 0, `zfhPtr` is correctly filled,
+ * >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
+{
+ const BYTE* ip = (const BYTE*)src;
+ size_t const minInputSize = ZSTD_startingInputLength(format);
+
+ memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
+ if (srcSize < minInputSize) return minInputSize;
+ if (src==NULL) return ERROR(GENERIC); /* invalid parameter */
+
+ if ( (format != ZSTD_f_zstd1_magicless)
+ && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
+ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ /* skippable frame */
+ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
+ return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
+ memset(zfhPtr, 0, sizeof(*zfhPtr));
+ zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
+ zfhPtr->frameType = ZSTD_skippableFrame;
+ return 0;
+ }
+ return ERROR(prefix_unknown);
+ }
+
+ /* ensure there is enough `srcSize` to fully read/decode frame header */
+ { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
+ if (srcSize < fhsize) return fhsize;
+ zfhPtr->headerSize = (U32)fhsize;
+ }
+
+ { BYTE const fhdByte = ip[minInputSize-1];
+ size_t pos = minInputSize;
+ U32 const dictIDSizeCode = fhdByte&3;
+ U32 const checksumFlag = (fhdByte>>2)&1;
+ U32 const singleSegment = (fhdByte>>5)&1;
+ U32 const fcsID = fhdByte>>6;
+ U64 windowSize = 0;
+ U32 dictID = 0;
+ U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ if ((fhdByte & 0x08) != 0)
+ return ERROR(frameParameter_unsupported); /* reserved bits, must be zero */
+
+ if (!singleSegment) {
+ BYTE const wlByte = ip[pos++];
+ U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
+ if (windowLog > ZSTD_WINDOWLOG_MAX)
+ return ERROR(frameParameter_windowTooLarge);
+ windowSize = (1ULL << windowLog);
+ windowSize += (windowSize >> 3) * (wlByte&7);
+ }
+ switch(dictIDSizeCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : break;
+ case 1 : dictID = ip[pos]; pos++; break;
+ case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
+ case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
+ }
+ switch(fcsID)
+ {
+ default: assert(0); /* impossible */
+ case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
+ case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
+ case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
+ case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
+ }
+ if (singleSegment) windowSize = frameContentSize;
+
+ zfhPtr->frameType = ZSTD_frame;
+ zfhPtr->frameContentSize = frameContentSize;
+ zfhPtr->windowSize = windowSize;
+ zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ zfhPtr->dictID = dictID;
+ zfhPtr->checksumFlag = checksumFlag;
+ }
+ return 0;
+}
+
+/** ZSTD_getFrameHeader() :
+ * decode Frame Header, or require larger `srcSize`.
+ * note : this function does not consume input, it only reads it.
+ * @return : 0, `zfhPtr` is correctly filled,
+ * >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
+{
+ return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameContentSize() :
+ * compatible with legacy mode
+ * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
+ * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
+ * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
+unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
+{
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize)) {
+ unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
+ return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
+ }
+#endif
+ { ZSTD_frameHeader zfh;
+ if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
+ return ZSTD_CONTENTSIZE_ERROR;
+ if (zfh.frameType == ZSTD_skippableFrame) {
+ return 0;
+ } else {
+ return zfh.frameContentSize;
+ } }
+}
+
+static size_t readSkippableFrameSize(void const* src, size_t srcSize)
+{
+ size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
+ U32 sizeU32;
+
+ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
+ return ERROR(srcSize_wrong);
+
+ sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
+ if ((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32)
+ return ERROR(frameParameter_unsupported);
+
+ return skippableHeaderSize + sizeU32;
+}
+
+/** ZSTD_findDecompressedSize() :
+ * compatible with legacy mode
+ * `srcSize` must be the exact length of some number of ZSTD compressed and/or
+ * skippable frames
+ * @return : decompressed size of the frames contained */
+unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
+{
+ unsigned long long totalDstSize = 0;
+
+ while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
+ U32 const magicNumber = MEM_readLE32(src);
+
+ if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+ if (ZSTD_isError(skippableSize))
+ return skippableSize;
+ if (srcSize < skippableSize) {
+ return ZSTD_CONTENTSIZE_ERROR;
+ }
+
+ src = (const BYTE *)src + skippableSize;
+ srcSize -= skippableSize;
+ continue;
+ }
+
+ { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+ if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
+
+ /* check for overflow */
+ if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
+ totalDstSize += ret;
+ }
+ { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
+ if (ZSTD_isError(frameSrcSize)) {
+ return ZSTD_CONTENTSIZE_ERROR;
+ }
+
+ src = (const BYTE *)src + frameSrcSize;
+ srcSize -= frameSrcSize;
+ }
+ } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+ if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
+
+ return totalDstSize;
+}
+
+/** ZSTD_getDecompressedSize() :
+ * compatible with legacy mode
+ * @return : decompressed size if known, 0 otherwise
+ note : 0 can mean any of the following :
+ - frame content is empty
+ - decompressed size field is not present in frame header
+ - frame header unknown / not supported
+ - frame header not complete (`srcSize` too small) */
+unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
+{
+ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
+ return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
+}
+
+
+/** ZSTD_decodeFrameHeader() :
+ * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
+ * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
+static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
+{
+ size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
+ if (ZSTD_isError(result)) return result; /* invalid header */
+ if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
+ if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
+ return ERROR(dictionary_wrong);
+ if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
+ return 0;
+}
+
+
+/** ZSTD_findFrameCompressedSize() :
+ * compatible with legacy mode
+ * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
+ * `srcSize` must be at least as large as the frame contained
+ * @return : the compressed size of the frame starting at `src` */
+size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
+{
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize))
+ return ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
+#endif
+ if ( (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
+ && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START ) {
+ return readSkippableFrameSize(src, srcSize);
+ } else {
+ const BYTE* ip = (const BYTE*)src;
+ const BYTE* const ipstart = ip;
+ size_t remainingSize = srcSize;
+ ZSTD_frameHeader zfh;
+
+ /* Extract Frame Header */
+ { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
+ if (ZSTD_isError(ret)) return ret;
+ if (ret > 0) return ERROR(srcSize_wrong);
+ }
+
+ ip += zfh.headerSize;
+ remainingSize -= zfh.headerSize;
+
+ /* Loop on each block */
+ while (1) {
+ blockProperties_t blockProperties;
+ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
+ if (ZSTD_isError(cBlockSize)) return cBlockSize;
+
+ if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
+ return ERROR(srcSize_wrong);
+
+ ip += ZSTD_blockHeaderSize + cBlockSize;
+ remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
+
+ if (blockProperties.lastBlock) break;
+ }
+
+ if (zfh.checksumFlag) { /* Final frame content checksum */
+ if (remainingSize < 4) return ERROR(srcSize_wrong);
+ ip += 4;
+ }
+
+ return ip - ipstart;
+ }
+}
+
+
+
+/*-*************************************************************
+ * Frame decoding
+ ***************************************************************/
+
+
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+{
+ if (dst != dctx->previousDstEnd) { /* not contiguous */
+ dctx->dictEnd = dctx->previousDstEnd;
+ dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+ dctx->prefixStart = dst;
+ dctx->previousDstEnd = dst;
+ }
+}
+
+/** ZSTD_insertBlock() :
+ insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
+size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
+{
+ ZSTD_checkContinuity(dctx, blockStart);
+ dctx->previousDstEnd = (const char*)blockStart + blockSize;
+ return blockSize;
+}
+
+
+static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_copyRawBlock");
+ if (dst == NULL) {
+ if (srcSize == 0) return 0;
+ return ERROR(dstBuffer_null);
+ }
+ if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall);
+ memcpy(dst, src, srcSize);
+ return srcSize;
+}
+
+static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
+ BYTE b,
+ size_t regenSize)
+{
+ if (dst == NULL) {
+ if (regenSize == 0) return 0;
+ return ERROR(dstBuffer_null);
+ }
+ if (regenSize > dstCapacity) return ERROR(dstSize_tooSmall);
+ memset(dst, b, regenSize);
+ return regenSize;
+}
+
+
+/*! ZSTD_decompressFrame() :
+ * @dctx must be properly initialized
+ * will update *srcPtr and *srcSizePtr,
+ * to make *srcPtr progress by one frame. */
+static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void** srcPtr, size_t *srcSizePtr)
+{
+ const BYTE* ip = (const BYTE*)(*srcPtr);
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart;
+ size_t remainingSrcSize = *srcSizePtr;
+
+ DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
+
+ /* check */
+ if (remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN+ZSTD_blockHeaderSize)
+ return ERROR(srcSize_wrong);
+
+ /* Frame Header */
+ { size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_FRAMEHEADERSIZE_PREFIX);
+ if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
+ if (remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize)
+ return ERROR(srcSize_wrong);
+ CHECK_F( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) );
+ ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
+ }
+
+ /* Loop on each block */
+ while (1) {
+ size_t decodedSize;
+ blockProperties_t blockProperties;
+ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
+ if (ZSTD_isError(cBlockSize)) return cBlockSize;
+
+ ip += ZSTD_blockHeaderSize;
+ remainingSrcSize -= ZSTD_blockHeaderSize;
+ if (cBlockSize > remainingSrcSize) return ERROR(srcSize_wrong);
+
+ switch(blockProperties.blockType)
+ {
+ case bt_compressed:
+ decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
+ break;
+ case bt_raw :
+ decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
+ break;
+ case bt_rle :
+ decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
+ break;
+ case bt_reserved :
+ default:
+ return ERROR(corruption_detected);
+ }
+
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+ if (dctx->fParams.checksumFlag)
+ XXH64_update(&dctx->xxhState, op, decodedSize);
+ op += decodedSize;
+ ip += cBlockSize;
+ remainingSrcSize -= cBlockSize;
+ if (blockProperties.lastBlock) break;
+ }
+
+ if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ if ((U64)(op-ostart) != dctx->fParams.frameContentSize) {
+ return ERROR(corruption_detected);
+ } }
+ if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
+ U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
+ U32 checkRead;
+ if (remainingSrcSize<4) return ERROR(checksum_wrong);
+ checkRead = MEM_readLE32(ip);
+ if (checkRead != checkCalc) return ERROR(checksum_wrong);
+ ip += 4;
+ remainingSrcSize -= 4;
+ }
+
+ /* Allow caller to get size read */
+ *srcPtr = ip;
+ *srcSizePtr = remainingSrcSize;
+ return op-ostart;
+}
+
+static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize,
+ const ZSTD_DDict* ddict)
+{
+ void* const dststart = dst;
+ int moreThan1Frame = 0;
+
+ DEBUGLOG(5, "ZSTD_decompressMultiFrame");
+ assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */
+
+ if (ddict) {
+ dict = ZSTD_DDict_dictContent(ddict);
+ dictSize = ZSTD_DDict_dictSize(ddict);
+ }
+
+ while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize)) {
+ size_t decodedSize;
+ size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
+ if (ZSTD_isError(frameSize)) return frameSize;
+ /* legacy support is not compatible with static dctx */
+ if (dctx->staticSize) return ERROR(memory_allocation);
+
+ decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+
+ assert(decodedSize <=- dstCapacity);
+ dst = (BYTE*)dst + decodedSize;
+ dstCapacity -= decodedSize;
+
+ src = (const BYTE*)src + frameSize;
+ srcSize -= frameSize;
+
+ continue;
+ }
+#endif
+
+ { U32 const magicNumber = MEM_readLE32(src);
+ DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
+ (unsigned)magicNumber, ZSTD_MAGICNUMBER);
+ if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+ if (ZSTD_isError(skippableSize))
+ return skippableSize;
+ if (srcSize < skippableSize) return ERROR(srcSize_wrong);
+
+ src = (const BYTE *)src + skippableSize;
+ srcSize -= skippableSize;
+ continue;
+ } }
+
+ if (ddict) {
+ /* we were called from ZSTD_decompress_usingDDict */
+ CHECK_F(ZSTD_decompressBegin_usingDDict(dctx, ddict));
+ } else {
+ /* this will initialize correctly with no dict if dict == NULL, so
+ * use this in all cases but ddict */
+ CHECK_F(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize));
+ }
+ ZSTD_checkContinuity(dctx, dst);
+
+ { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
+ &src, &srcSize);
+ if ( (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
+ && (moreThan1Frame==1) ) {
+ /* at least one frame successfully completed,
+ * but following bytes are garbage :
+ * it's more likely to be a srcSize error,
+ * specifying more bytes than compressed size of frame(s).
+ * This error message replaces ERROR(prefix_unknown),
+ * which would be confusing, as the first header is actually correct.
+ * Note that one could be unlucky, it might be a corruption error instead,
+ * happening right at the place where we expect zstd magic bytes.
+ * But this is _much_ less likely than a srcSize field error. */
+ return ERROR(srcSize_wrong);
+ }
+ if (ZSTD_isError(res)) return res;
+ assert(res <= dstCapacity);
+ dst = (BYTE*)dst + res;
+ dstCapacity -= res;
+ }
+ moreThan1Frame = 1;
+ } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+ if (srcSize) return ERROR(srcSize_wrong); /* input not entirely consumed */
+
+ return (BYTE*)dst - (BYTE*)dststart;
+}
+
+size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize)
+{
+ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
+}
+
+
+size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);
+}
+
+
+size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
+ size_t regenSize;
+ ZSTD_DCtx* const dctx = ZSTD_createDCtx();
+ if (dctx==NULL) return ERROR(memory_allocation);
+ regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
+ ZSTD_freeDCtx(dctx);
+ return regenSize;
+#else /* stack mode */
+ ZSTD_DCtx dctx;
+ ZSTD_initDCtx_internal(&dctx);
+ return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
+#endif
+}
+
+
+/*-**************************************
+* Advanced Streaming Decompression API
+* Bufferless and synchronous
+****************************************/
+size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
+
+ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
+ switch(dctx->stage)
+ {
+ default: /* should not happen */
+ assert(0);
+ case ZSTDds_getFrameHeaderSize:
+ case ZSTDds_decodeFrameHeader:
+ return ZSTDnit_frameHeader;
+ case ZSTDds_decodeBlockHeader:
+ return ZSTDnit_blockHeader;
+ case ZSTDds_decompressBlock:
+ return ZSTDnit_block;
+ case ZSTDds_decompressLastBlock:
+ return ZSTDnit_lastBlock;
+ case ZSTDds_checkChecksum:
+ return ZSTDnit_checksum;
+ case ZSTDds_decodeSkippableHeader:
+ case ZSTDds_skipFrame:
+ return ZSTDnit_skippableFrame;
+ }
+}
+
+static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
+
+/** ZSTD_decompressContinue() :
+ * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
+ * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
+ /* Sanity check */
+ if (srcSize != dctx->expected)
+ return ERROR(srcSize_wrong); /* not allowed */
+ if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+
+ switch (dctx->stage)
+ {
+ case ZSTDds_getFrameHeaderSize :
+ assert(src != NULL);
+ if (dctx->format == ZSTD_f_zstd1) { /* allows header */
+ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */
+ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
+ memcpy(dctx->headerBuffer, src, srcSize);
+ dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */
+ dctx->stage = ZSTDds_decodeSkippableHeader;
+ return 0;
+ } }
+ dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
+ if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
+ memcpy(dctx->headerBuffer, src, srcSize);
+ dctx->expected = dctx->headerSize - srcSize;
+ dctx->stage = ZSTDds_decodeFrameHeader;
+ return 0;
+
+ case ZSTDds_decodeFrameHeader:
+ assert(src != NULL);
+ memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
+ CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
+ dctx->expected = ZSTD_blockHeaderSize;
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ return 0;
+
+ case ZSTDds_decodeBlockHeader:
+ { blockProperties_t bp;
+ size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
+ if (ZSTD_isError(cBlockSize)) return cBlockSize;
+ dctx->expected = cBlockSize;
+ dctx->bType = bp.blockType;
+ dctx->rleSize = bp.origSize;
+ if (cBlockSize) {
+ dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
+ return 0;
+ }
+ /* empty block */
+ if (bp.lastBlock) {
+ if (dctx->fParams.checksumFlag) {
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* end of frame */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ }
+ return 0;
+ }
+
+ case ZSTDds_decompressLastBlock:
+ case ZSTDds_decompressBlock:
+ DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
+ { size_t rSize;
+ switch(dctx->bType)
+ {
+ case bt_compressed:
+ DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
+ rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
+ break;
+ case bt_raw :
+ rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
+ break;
+ case bt_rle :
+ rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
+ break;
+ case bt_reserved : /* should never happen */
+ default:
+ return ERROR(corruption_detected);
+ }
+ if (ZSTD_isError(rSize)) return rSize;
+ DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
+ dctx->decodedSize += rSize;
+ if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
+
+ if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
+ DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
+ if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ if (dctx->decodedSize != dctx->fParams.frameContentSize) {
+ return ERROR(corruption_detected);
+ } }
+ if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* ends here */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ dctx->expected = ZSTD_blockHeaderSize;
+ dctx->previousDstEnd = (char*)dst + rSize;
+ }
+ return rSize;
+ }
+
+ case ZSTDds_checkChecksum:
+ assert(srcSize == 4); /* guaranteed by dctx->expected */
+ { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
+ U32 const check32 = MEM_readLE32(src);
+ DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
+ if (check32 != h32) return ERROR(checksum_wrong);
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+ }
+
+ case ZSTDds_decodeSkippableHeader:
+ assert(src != NULL);
+ assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
+ memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
+ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
+ dctx->stage = ZSTDds_skipFrame;
+ return 0;
+
+ case ZSTDds_skipFrame:
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+
+ default:
+ assert(0); /* impossible */
+ return ERROR(GENERIC); /* some compiler require default to do something */
+ }
+}
+
+
+static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ dctx->dictEnd = dctx->previousDstEnd;
+ dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+ dctx->prefixStart = dict;
+ dctx->previousDstEnd = (const char*)dict + dictSize;
+ return 0;
+}
+
+/*! ZSTD_loadDEntropy() :
+ * dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of entropy tables read */
+size_t
+ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+ const void* const dict, size_t const dictSize)
+{
+ const BYTE* dictPtr = (const BYTE*)dict;
+ const BYTE* const dictEnd = dictPtr + dictSize;
+
+ if (dictSize <= 8) return ERROR(dictionary_corrupted);
+ assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */
+ dictPtr += 8; /* skip header = magic + dictID */
+
+ ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
+ ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
+ ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
+ { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */
+ size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
+#ifdef HUF_FORCE_DECOMPRESS_X1
+ /* in minimal huffman, we always use X1 variants */
+ size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
+ dictPtr, dictEnd - dictPtr,
+ workspace, workspaceSize);
+#else
+ size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
+ dictPtr, dictEnd - dictPtr,
+ workspace, workspaceSize);
+#endif
+ if (HUF_isError(hSize)) return ERROR(dictionary_corrupted);
+ dictPtr += hSize;
+ }
+
+ { short offcodeNCount[MaxOff+1];
+ unsigned offcodeMaxValue = MaxOff, offcodeLog;
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
+ if (offcodeMaxValue > MaxOff) return ERROR(dictionary_corrupted);
+ if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
+ ZSTD_buildFSETable( entropy->OFTable,
+ offcodeNCount, offcodeMaxValue,
+ OF_base, OF_bits,
+ offcodeLog);
+ dictPtr += offcodeHeaderSize;
+ }
+
+ { short matchlengthNCount[MaxML+1];
+ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
+ if (matchlengthMaxValue > MaxML) return ERROR(dictionary_corrupted);
+ if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
+ ZSTD_buildFSETable( entropy->MLTable,
+ matchlengthNCount, matchlengthMaxValue,
+ ML_base, ML_bits,
+ matchlengthLog);
+ dictPtr += matchlengthHeaderSize;
+ }
+
+ { short litlengthNCount[MaxLL+1];
+ unsigned litlengthMaxValue = MaxLL, litlengthLog;
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+ if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
+ if (litlengthMaxValue > MaxLL) return ERROR(dictionary_corrupted);
+ if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
+ ZSTD_buildFSETable( entropy->LLTable,
+ litlengthNCount, litlengthMaxValue,
+ LL_base, LL_bits,
+ litlengthLog);
+ dictPtr += litlengthHeaderSize;
+ }
+
+ if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
+ { int i;
+ size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
+ for (i=0; i<3; i++) {
+ U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
+ if (rep==0 || rep >= dictContentSize) return ERROR(dictionary_corrupted);
+ entropy->rep[i] = rep;
+ } }
+
+ return dictPtr - (const BYTE*)dict;
+}
+
+static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
+ { U32 const magic = MEM_readLE32(dict);
+ if (magic != ZSTD_MAGIC_DICTIONARY) {
+ return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
+ } }
+ dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+
+ /* load entropy tables */
+ { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
+ if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted);
+ dict = (const char*)dict + eSize;
+ dictSize -= eSize;
+ }
+ dctx->litEntropy = dctx->fseEntropy = 1;
+
+ /* reference dictionary content */
+ return ZSTD_refDictContent(dctx, dict, dictSize);
+}
+
+size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
+{
+ assert(dctx != NULL);
+ dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ dctx->decodedSize = 0;
+ dctx->previousDstEnd = NULL;
+ dctx->prefixStart = NULL;
+ dctx->virtualStart = NULL;
+ dctx->dictEnd = NULL;
+ dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+ dctx->litEntropy = dctx->fseEntropy = 0;
+ dctx->dictID = 0;
+ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
+ memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
+ dctx->LLTptr = dctx->entropy.LLTable;
+ dctx->MLTptr = dctx->entropy.MLTable;
+ dctx->OFTptr = dctx->entropy.OFTable;
+ dctx->HUFptr = dctx->entropy.hufTable;
+ return 0;
+}
+
+size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ CHECK_F( ZSTD_decompressBegin(dctx) );
+ if (dict && dictSize)
+ CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted);
+ return 0;
+}
+
+
+/* ====== ZSTD_DDict ====== */
+
+size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
+ assert(dctx != NULL);
+ if (ddict) {
+ const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
+ size_t const dictSize = ZSTD_DDict_dictSize(ddict);
+ const void* const dictEnd = dictStart + dictSize;
+ dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
+ DEBUGLOG(4, "DDict is %s",
+ dctx->ddictIsCold ? "~cold~" : "hot!");
+ }
+ CHECK_F( ZSTD_decompressBegin(dctx) );
+ if (ddict) { /* NULL ddict is equivalent to no dictionary */
+ ZSTD_copyDDictParameters(dctx, ddict);
+ }
+ return 0;
+}
+
+/*! ZSTD_getDictID_fromDict() :
+ * Provides the dictID stored within dictionary.
+ * if @return == 0, the dictionary is not conformant with Zstandard specification.
+ * It can still be loaded, but as a content-only dictionary. */
+unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
+{
+ if (dictSize < 8) return 0;
+ if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
+ return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+}
+
+/*! ZSTD_getDictID_fromFrame() :
+ * Provides the dictID required to decompresse frame stored within `src`.
+ * If @return == 0, the dictID could not be decoded.
+ * This could for one of the following reasons :
+ * - The frame does not require a dictionary (most common case).
+ * - The frame was built with dictID intentionally removed.
+ * Needed dictionary is a hidden information.
+ * Note : this use case also happens when using a non-conformant dictionary.
+ * - `srcSize` is too small, and as a result, frame header could not be decoded.
+ * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
+ * - This is not a Zstandard frame.
+ * When identifying the exact failure cause, it's possible to use
+ * ZSTD_getFrameHeader(), which will provide a more precise error code. */
+unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
+{
+ ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
+ size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
+ if (ZSTD_isError(hError)) return 0;
+ return zfp.dictID;
+}
+
+
+/*! ZSTD_decompress_usingDDict() :
+* Decompression using a pre-digested Dictionary
+* Use dictionary without significant overhead. */
+size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_DDict* ddict)
+{
+ /* pass content and size in case legacy frames are encountered */
+ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
+ NULL, 0,
+ ddict);
+}
+
+
+/*=====================================
+* Streaming decompression
+*====================================*/
+
+ZSTD_DStream* ZSTD_createDStream(void)
+{
+ DEBUGLOG(3, "ZSTD_createDStream");
+ return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
+{
+ return ZSTD_initStaticDCtx(workspace, workspaceSize);
+}
+
+ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
+{
+ return ZSTD_createDCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeDStream(ZSTD_DStream* zds)
+{
+ return ZSTD_freeDCtx(zds);
+}
+
+
+/* *** Initialization *** */
+
+size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
+size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+ ZSTD_freeDDict(dctx->ddictLocal);
+ if (dict && dictSize >= 8) {
+ dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
+ if (dctx->ddictLocal == NULL) return ERROR(memory_allocation);
+ } else {
+ dctx->ddictLocal = NULL;
+ }
+ dctx->ddict = dctx->ddictLocal;
+ return 0;
+}
+
+size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+ return ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType);
+}
+
+size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
+{
+ return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+
+/* ZSTD_initDStream_usingDict() :
+ * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
+{
+ DEBUGLOG(4, "ZSTD_initDStream_usingDict");
+ zds->streamStage = zdss_init;
+ zds->noForwardProgress = 0;
+ CHECK_F( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
+ return ZSTD_FRAMEHEADERSIZE_PREFIX;
+}
+
+/* note : this variant can't fail */
+size_t ZSTD_initDStream(ZSTD_DStream* zds)
+{
+ DEBUGLOG(4, "ZSTD_initDStream");
+ return ZSTD_initDStream_usingDict(zds, NULL, 0);
+}
+
+/* ZSTD_initDStream_usingDDict() :
+ * ddict will just be referenced, and must outlive decompression session
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
+{
+ size_t const initResult = ZSTD_initDStream(dctx);
+ dctx->ddict = ddict;
+ return initResult;
+}
+
+/* ZSTD_resetDStream() :
+ * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * this function cannot fail */
+size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
+{
+ DEBUGLOG(4, "ZSTD_resetDStream");
+ dctx->streamStage = zdss_loadHeader;
+ dctx->lhSize = dctx->inPos = dctx->outStart = dctx->outEnd = 0;
+ dctx->legacyVersion = 0;
+ dctx->hostageByte = 0;
+ return ZSTD_FRAMEHEADERSIZE_PREFIX;
+}
+
+
+size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+ dctx->ddict = ddict;
+ return 0;
+}
+
+/* ZSTD_DCtx_setMaxWindowSize() :
+ * note : no direct equivalence in ZSTD_DCtx_setParameter,
+ * since this version sets windowSize, and the other sets windowLog */
+size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
+{
+ ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
+ size_t const min = (size_t)1 << bounds.lowerBound;
+ size_t const max = (size_t)1 << bounds.upperBound;
+ if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+ if (maxWindowSize < min) return ERROR(parameter_outOfBound);
+ if (maxWindowSize > max) return ERROR(parameter_outOfBound);
+ dctx->maxWindowSize = maxWindowSize;
+ return 0;
+}
+
+size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
+{
+ return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
+}
+
+ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
+{
+ ZSTD_bounds bounds = { 0, 0, 0 };
+ switch(dParam) {
+ case ZSTD_d_windowLogMax:
+ bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
+ bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+ return bounds;
+ case ZSTD_d_format:
+ bounds.lowerBound = (int)ZSTD_f_zstd1;
+ bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
+ ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+ return bounds;
+ default:;
+ }
+ bounds.error = ERROR(parameter_unsupported);
+ return bounds;
+}
+
+/* ZSTD_dParam_withinBounds:
+ * @return 1 if value is within dParam bounds,
+ * 0 otherwise */
+static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
+{
+ ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
+ if (ZSTD_isError(bounds.error)) return 0;
+ if (value < bounds.lowerBound) return 0;
+ if (value > bounds.upperBound) return 0;
+ return 1;
+}
+
+#define CHECK_DBOUNDS(p,v) { \
+ if (!ZSTD_dParam_withinBounds(p, v)) \
+ return ERROR(parameter_outOfBound); \
+}
+
+size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
+{
+ if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+ switch(dParam) {
+ case ZSTD_d_windowLogMax:
+ CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
+ dctx->maxWindowSize = ((size_t)1) << value;
+ return 0;
+ case ZSTD_d_format:
+ CHECK_DBOUNDS(ZSTD_d_format, value);
+ dctx->format = (ZSTD_format_e)value;
+ return 0;
+ default:;
+ }
+ return ERROR(parameter_unsupported);
+}
+
+size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
+{
+ if ( (reset == ZSTD_reset_session_only)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ (void)ZSTD_initDStream(dctx);
+ }
+ if ( (reset == ZSTD_reset_parameters)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ if (dctx->streamStage != zdss_init)
+ return ERROR(stage_wrong);
+ dctx->format = ZSTD_f_zstd1;
+ dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+ }
+ return 0;
+}
+
+
+size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
+{
+ return ZSTD_sizeof_DCtx(dctx);
+}
+
+size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
+{
+ size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
+ unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
+ size_t const minRBSize = (size_t) neededSize;
+ if ((unsigned long long)minRBSize != neededSize) return ERROR(frameParameter_windowTooLarge);
+ return minRBSize;
+}
+
+size_t ZSTD_estimateDStreamSize(size_t windowSize)
+{
+ size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ size_t const inBuffSize = blockSize; /* no block can be larger */
+ size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
+ return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
+}
+
+size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
+{
+ U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
+ ZSTD_frameHeader zfh;
+ size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
+ if (ZSTD_isError(err)) return err;
+ if (err>0) return ERROR(srcSize_wrong);
+ if (zfh.windowSize > windowSizeMax)
+ return ERROR(frameParameter_windowTooLarge);
+ return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
+}
+
+
+/* ***** Decompression ***** */
+
+MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ size_t const length = MIN(dstCapacity, srcSize);
+ memcpy(dst, src, length);
+ return length;
+}
+
+
+size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ const char* const istart = (const char*)(input->src) + input->pos;
+ const char* const iend = (const char*)(input->src) + input->size;
+ const char* ip = istart;
+ char* const ostart = (char*)(output->dst) + output->pos;
+ char* const oend = (char*)(output->dst) + output->size;
+ char* op = ostart;
+ U32 someMoreWork = 1;
+
+ DEBUGLOG(5, "ZSTD_decompressStream");
+ if (input->pos > input->size) { /* forbidden */
+ DEBUGLOG(5, "in: pos: %u vs size: %u",
+ (U32)input->pos, (U32)input->size);
+ return ERROR(srcSize_wrong);
+ }
+ if (output->pos > output->size) { /* forbidden */
+ DEBUGLOG(5, "out: pos: %u vs size: %u",
+ (U32)output->pos, (U32)output->size);
+ return ERROR(dstSize_tooSmall);
+ }
+ DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
+
+ while (someMoreWork) {
+ switch(zds->streamStage)
+ {
+ case zdss_init :
+ DEBUGLOG(5, "stage zdss_init => transparent reset ");
+ ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
+ /* fall-through */
+
+ case zdss_loadHeader :
+ DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+ if (zds->legacyVersion) {
+ /* legacy support is incompatible with static dctx */
+ if (zds->staticSize) return ERROR(memory_allocation);
+ { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
+ if (hint==0) zds->streamStage = zdss_init;
+ return hint;
+ } }
+#endif
+ { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
+ DEBUGLOG(5, "header size : %u", (U32)hSize);
+ if (ZSTD_isError(hSize)) {
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+ U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
+ if (legacyVersion) {
+ const void* const dict = zds->ddict ? ZSTD_DDict_dictContent(zds->ddict) : NULL;
+ size_t const dictSize = zds->ddict ? ZSTD_DDict_dictSize(zds->ddict) : 0;
+ DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
+ /* legacy support is incompatible with static dctx */
+ if (zds->staticSize) return ERROR(memory_allocation);
+ CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext,
+ zds->previousLegacyVersion, legacyVersion,
+ dict, dictSize));
+ zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
+ { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
+ if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
+ return hint;
+ } }
+#endif
+ return hSize; /* error */
+ }
+ if (hSize != 0) { /* need more input */
+ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
+ size_t const remainingInput = (size_t)(iend-ip);
+ assert(iend >= ip);
+ if (toLoad > remainingInput) { /* not enough input to load full header */
+ if (remainingInput > 0) {
+ memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
+ zds->lhSize += remainingInput;
+ }
+ input->pos = input->size;
+ return (MAX(ZSTD_FRAMEHEADERSIZE_MIN, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
+ }
+ assert(ip != NULL);
+ memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
+ break;
+ } }
+
+ /* check for single-pass mode opportunity */
+ if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
+ && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
+ size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
+ if (cSize <= (size_t)(iend-istart)) {
+ /* shortcut : using single-pass mode */
+ size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, zds->ddict);
+ if (ZSTD_isError(decompressedSize)) return decompressedSize;
+ DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
+ ip = istart + cSize;
+ op += decompressedSize;
+ zds->expected = 0;
+ zds->streamStage = zdss_init;
+ someMoreWork = 0;
+ break;
+ } }
+
+ /* Consume header (see ZSTDds_decodeFrameHeader) */
+ DEBUGLOG(4, "Consume header");
+ CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict));
+
+ if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
+ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
+ zds->stage = ZSTDds_skipFrame;
+ } else {
+ CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
+ zds->expected = ZSTD_blockHeaderSize;
+ zds->stage = ZSTDds_decodeBlockHeader;
+ }
+
+ /* control buffer memory usage */
+ DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
+ (U32)(zds->fParams.windowSize >>10),
+ (U32)(zds->maxWindowSize >> 10) );
+ zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
+ if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
+
+ /* Adapt buffer sizes to frame header instructions */
+ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
+ size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize);
+ if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) {
+ size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
+ DEBUGLOG(4, "inBuff : from %u to %u",
+ (U32)zds->inBuffSize, (U32)neededInBuffSize);
+ DEBUGLOG(4, "outBuff : from %u to %u",
+ (U32)zds->outBuffSize, (U32)neededOutBuffSize);
+ if (zds->staticSize) { /* static DCtx */
+ DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
+ assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
+ if (bufferSize > zds->staticSize - sizeof(ZSTD_DCtx))
+ return ERROR(memory_allocation);
+ } else {
+ ZSTD_free(zds->inBuff, zds->customMem);
+ zds->inBuffSize = 0;
+ zds->outBuffSize = 0;
+ zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
+ if (zds->inBuff == NULL) return ERROR(memory_allocation);
+ }
+ zds->inBuffSize = neededInBuffSize;
+ zds->outBuff = zds->inBuff + zds->inBuffSize;
+ zds->outBuffSize = neededOutBuffSize;
+ } }
+ zds->streamStage = zdss_read;
+ /* fall-through */
+
+ case zdss_read:
+ DEBUGLOG(5, "stage zdss_read");
+ { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
+ DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
+ if (neededInSize==0) { /* end of frame */
+ zds->streamStage = zdss_init;
+ someMoreWork = 0;
+ break;
+ }
+ if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
+ int const isSkipFrame = ZSTD_isSkipFrame(zds);
+ size_t const decodedSize = ZSTD_decompressContinue(zds,
+ zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),
+ ip, neededInSize);
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+ ip += neededInSize;
+ if (!decodedSize && !isSkipFrame) break; /* this was just a header */
+ zds->outEnd = zds->outStart + decodedSize;
+ zds->streamStage = zdss_flush;
+ break;
+ } }
+ if (ip==iend) { someMoreWork = 0; break; } /* no more input */
+ zds->streamStage = zdss_load;
+ /* fall-through */
+
+ case zdss_load:
+ { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
+ size_t const toLoad = neededInSize - zds->inPos;
+ int const isSkipFrame = ZSTD_isSkipFrame(zds);
+ size_t loadedSize;
+ if (isSkipFrame) {
+ loadedSize = MIN(toLoad, (size_t)(iend-ip));
+ } else {
+ if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */
+ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
+ }
+ ip += loadedSize;
+ zds->inPos += loadedSize;
+ if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
+
+ /* decode loaded input */
+ { size_t const decodedSize = ZSTD_decompressContinue(zds,
+ zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
+ zds->inBuff, neededInSize);
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+ zds->inPos = 0; /* input is consumed */
+ if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */
+ zds->outEnd = zds->outStart + decodedSize;
+ } }
+ zds->streamStage = zdss_flush;
+ /* fall-through */
+
+ case zdss_flush:
+ { size_t const toFlushSize = zds->outEnd - zds->outStart;
+ size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
+ op += flushedSize;
+ zds->outStart += flushedSize;
+ if (flushedSize == toFlushSize) { /* flush completed */
+ zds->streamStage = zdss_read;
+ if ( (zds->outBuffSize < zds->fParams.frameContentSize)
+ && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
+ DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
+ (int)(zds->outBuffSize - zds->outStart),
+ (U32)zds->fParams.blockSizeMax);
+ zds->outStart = zds->outEnd = 0;
+ }
+ break;
+ } }
+ /* cannot complete flush */
+ someMoreWork = 0;
+ break;
+
+ default:
+ assert(0); /* impossible */
+ return ERROR(GENERIC); /* some compiler require default to do something */
+ } }
+
+ /* result */
+ input->pos = (size_t)(ip - (const char*)(input->src));
+ output->pos = (size_t)(op - (char*)(output->dst));
+ if ((ip==istart) && (op==ostart)) { /* no forward progress */
+ zds->noForwardProgress ++;
+ if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
+ if (op==oend) return ERROR(dstSize_tooSmall);
+ if (ip==iend) return ERROR(srcSize_wrong);
+ assert(0);
+ }
+ } else {
+ zds->noForwardProgress = 0;
+ }
+ { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
+ if (!nextSrcSizeHint) { /* frame fully decoded */
+ if (zds->outEnd == zds->outStart) { /* output fully flushed */
+ if (zds->hostageByte) {
+ if (input->pos >= input->size) {
+ /* can't release hostage (not present) */
+ zds->streamStage = zdss_read;
+ return 1;
+ }
+ input->pos++; /* release hostage */
+ } /* zds->hostageByte */
+ return 0;
+ } /* zds->outEnd == zds->outStart */
+ if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
+ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
+ zds->hostageByte=1;
+ }
+ return 1;
+ } /* nextSrcSizeHint==0 */
+ nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
+ assert(zds->inPos <= nextSrcSizeHint);
+ nextSrcSizeHint -= zds->inPos; /* part already loaded*/
+ return nextSrcSizeHint;
+ }
+}
+
+size_t ZSTD_decompressStream_simpleArgs (
+ ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos)
+{
+ ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+ ZSTD_inBuffer input = { src, srcSize, *srcPos };
+ /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
+ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
+ *dstPos = output.pos;
+ *srcPos = input.pos;
+ return cErr;
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c
new file mode 100644
index 000000000..32baad9fb
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c
@@ -0,0 +1,1307 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_decompress_block :
+ * this module takes care of decompressing _compressed_ block */
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "compiler.h" /* prefetch */
+#include "cpu.h" /* bmi2 */
+#include "mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_internal.h"
+#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
+#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h"
+
+/*_*******************************************************
+* Macros
+**********************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * ZSTD_decompressSequences implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!"
+#endif
+
+
+/*_*******************************************************
+* Memory operations
+**********************************************************/
+static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
+
+
+/*-*************************************************************
+ * Block decoding
+ ***************************************************************/
+
+/*! ZSTD_getcBlockSize() :
+ * Provides the size of compressed block from block header `src` */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+ blockProperties_t* bpPtr)
+{
+ if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
+ { U32 const cBlockHeader = MEM_readLE24(src);
+ U32 const cSize = cBlockHeader >> 3;
+ bpPtr->lastBlock = cBlockHeader & 1;
+ bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
+ bpPtr->origSize = cSize; /* only useful for RLE */
+ if (bpPtr->blockType == bt_rle) return 1;
+ if (bpPtr->blockType == bt_reserved) return ERROR(corruption_detected);
+ return cSize;
+ }
+}
+
+
+/* Hidden declaration for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+ const void* src, size_t srcSize);
+/*! ZSTD_decodeLiteralsBlock() :
+ * @return : nb of bytes read from src (< srcSize )
+ * note : symbol not declared but exposed for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+ const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
+{
+ if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
+
+ { const BYTE* const istart = (const BYTE*) src;
+ symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
+
+ switch(litEncType)
+ {
+ case set_repeat:
+ if (dctx->litEntropy==0) return ERROR(dictionary_corrupted);
+ /* fall-through */
+
+ case set_compressed:
+ if (srcSize < 5) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
+ { size_t lhSize, litSize, litCSize;
+ U32 singleStream=0;
+ U32 const lhlCode = (istart[0] >> 2) & 3;
+ U32 const lhc = MEM_readLE32(istart);
+ size_t hufSuccess;
+ switch(lhlCode)
+ {
+ case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */
+ /* 2 - 2 - 10 - 10 */
+ singleStream = !lhlCode;
+ lhSize = 3;
+ litSize = (lhc >> 4) & 0x3FF;
+ litCSize = (lhc >> 14) & 0x3FF;
+ break;
+ case 2:
+ /* 2 - 2 - 14 - 14 */
+ lhSize = 4;
+ litSize = (lhc >> 4) & 0x3FFF;
+ litCSize = lhc >> 18;
+ break;
+ case 3:
+ /* 2 - 2 - 18 - 18 */
+ lhSize = 5;
+ litSize = (lhc >> 4) & 0x3FFFF;
+ litCSize = (lhc >> 22) + (istart[4] << 10);
+ break;
+ }
+ if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
+ if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
+
+ /* prefetch huffman table if cold */
+ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) {
+ PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable));
+ }
+
+ if (litEncType==set_repeat) {
+ if (singleStream) {
+ hufSuccess = HUF_decompress1X_usingDTable_bmi2(
+ dctx->litBuffer, litSize, istart+lhSize, litCSize,
+ dctx->HUFptr, dctx->bmi2);
+ } else {
+ hufSuccess = HUF_decompress4X_usingDTable_bmi2(
+ dctx->litBuffer, litSize, istart+lhSize, litCSize,
+ dctx->HUFptr, dctx->bmi2);
+ }
+ } else {
+ if (singleStream) {
+#if defined(HUF_FORCE_DECOMPRESS_X2)
+ hufSuccess = HUF_decompress1X_DCtx_wksp(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace));
+#else
+ hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace), dctx->bmi2);
+#endif
+ } else {
+ hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace), dctx->bmi2);
+ }
+ }
+
+ if (HUF_isError(hufSuccess)) return ERROR(corruption_detected);
+
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ dctx->litEntropy = 1;
+ if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
+ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+ return litCSize + lhSize;
+ }
+
+ case set_basic:
+ { size_t litSize, lhSize;
+ U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ switch(lhlCode)
+ {
+ case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = MEM_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = MEM_readLE24(istart) >> 4;
+ break;
+ }
+
+ if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
+ if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
+ memcpy(dctx->litBuffer, istart+lhSize, litSize);
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+ return lhSize+litSize;
+ }
+ /* direct reference into compressed stream */
+ dctx->litPtr = istart+lhSize;
+ dctx->litSize = litSize;
+ return lhSize+litSize;
+ }
+
+ case set_rle:
+ { U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ size_t litSize, lhSize;
+ switch(lhlCode)
+ {
+ case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = MEM_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = MEM_readLE24(istart) >> 4;
+ if (srcSize<4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
+ break;
+ }
+ if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
+ memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ return lhSize+1;
+ }
+ default:
+ return ERROR(corruption_detected); /* impossible */
+ }
+ }
+}
+
+/* Default FSE distribution tables.
+ * These are pre-calculated FSE decoding tables using default distributions as defined in specification :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
+ * They were generated programmatically with following method :
+ * - start from default distributions, present in /lib/common/zstd_internal.h
+ * - generate tables normally, using ZSTD_buildFSETable()
+ * - printout the content of tables
+ * - pretify output, report below, test with fuzzer to ensure it's correct */
+
+/* Default FSE distribution table for Literal Lengths */
+static const ZSTD_seqSymbol LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, LL_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 4, 0}, { 16, 0, 4, 0},
+ { 32, 0, 5, 1}, { 0, 0, 5, 3},
+ { 0, 0, 5, 4}, { 0, 0, 5, 6},
+ { 0, 0, 5, 7}, { 0, 0, 5, 9},
+ { 0, 0, 5, 10}, { 0, 0, 5, 12},
+ { 0, 0, 6, 14}, { 0, 1, 5, 16},
+ { 0, 1, 5, 20}, { 0, 1, 5, 22},
+ { 0, 2, 5, 28}, { 0, 3, 5, 32},
+ { 0, 4, 5, 48}, { 32, 6, 5, 64},
+ { 0, 7, 5, 128}, { 0, 8, 6, 256},
+ { 0, 10, 6, 1024}, { 0, 12, 6, 4096},
+ { 32, 0, 4, 0}, { 0, 0, 4, 1},
+ { 0, 0, 5, 2}, { 32, 0, 5, 4},
+ { 0, 0, 5, 5}, { 32, 0, 5, 7},
+ { 0, 0, 5, 8}, { 32, 0, 5, 10},
+ { 0, 0, 5, 11}, { 0, 0, 6, 13},
+ { 32, 1, 5, 16}, { 0, 1, 5, 18},
+ { 32, 1, 5, 22}, { 0, 2, 5, 24},
+ { 32, 3, 5, 32}, { 0, 3, 5, 40},
+ { 0, 6, 4, 64}, { 16, 6, 4, 64},
+ { 32, 7, 5, 128}, { 0, 9, 6, 512},
+ { 0, 11, 6, 2048}, { 48, 0, 4, 0},
+ { 16, 0, 4, 1}, { 32, 0, 5, 2},
+ { 32, 0, 5, 3}, { 32, 0, 5, 5},
+ { 32, 0, 5, 6}, { 32, 0, 5, 8},
+ { 32, 0, 5, 9}, { 32, 0, 5, 11},
+ { 32, 0, 5, 12}, { 0, 0, 6, 15},
+ { 32, 1, 5, 18}, { 32, 1, 5, 20},
+ { 32, 2, 5, 24}, { 32, 2, 5, 28},
+ { 32, 3, 5, 40}, { 32, 4, 5, 48},
+ { 0, 16, 6,65536}, { 0, 15, 6,32768},
+ { 0, 14, 6,16384}, { 0, 13, 6, 8192},
+}; /* LL_defaultDTable */
+
+/* Default FSE distribution table for Offset Codes */
+static const ZSTD_seqSymbol OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, OF_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 5, 0}, { 0, 6, 4, 61},
+ { 0, 9, 5, 509}, { 0, 15, 5,32765},
+ { 0, 21, 5,2097149}, { 0, 3, 5, 5},
+ { 0, 7, 4, 125}, { 0, 12, 5, 4093},
+ { 0, 18, 5,262141}, { 0, 23, 5,8388605},
+ { 0, 5, 5, 29}, { 0, 8, 4, 253},
+ { 0, 14, 5,16381}, { 0, 20, 5,1048573},
+ { 0, 2, 5, 1}, { 16, 7, 4, 125},
+ { 0, 11, 5, 2045}, { 0, 17, 5,131069},
+ { 0, 22, 5,4194301}, { 0, 4, 5, 13},
+ { 16, 8, 4, 253}, { 0, 13, 5, 8189},
+ { 0, 19, 5,524285}, { 0, 1, 5, 1},
+ { 16, 6, 4, 61}, { 0, 10, 5, 1021},
+ { 0, 16, 5,65533}, { 0, 28, 5,268435453},
+ { 0, 27, 5,134217725}, { 0, 26, 5,67108861},
+ { 0, 25, 5,33554429}, { 0, 24, 5,16777213},
+}; /* OF_defaultDTable */
+
+
+/* Default FSE distribution table for Match Lengths */
+static const ZSTD_seqSymbol ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, ML_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 6, 3}, { 0, 0, 4, 4},
+ { 32, 0, 5, 5}, { 0, 0, 5, 6},
+ { 0, 0, 5, 8}, { 0, 0, 5, 9},
+ { 0, 0, 5, 11}, { 0, 0, 6, 13},
+ { 0, 0, 6, 16}, { 0, 0, 6, 19},
+ { 0, 0, 6, 22}, { 0, 0, 6, 25},
+ { 0, 0, 6, 28}, { 0, 0, 6, 31},
+ { 0, 0, 6, 34}, { 0, 1, 6, 37},
+ { 0, 1, 6, 41}, { 0, 2, 6, 47},
+ { 0, 3, 6, 59}, { 0, 4, 6, 83},
+ { 0, 7, 6, 131}, { 0, 9, 6, 515},
+ { 16, 0, 4, 4}, { 0, 0, 4, 5},
+ { 32, 0, 5, 6}, { 0, 0, 5, 7},
+ { 32, 0, 5, 9}, { 0, 0, 5, 10},
+ { 0, 0, 6, 12}, { 0, 0, 6, 15},
+ { 0, 0, 6, 18}, { 0, 0, 6, 21},
+ { 0, 0, 6, 24}, { 0, 0, 6, 27},
+ { 0, 0, 6, 30}, { 0, 0, 6, 33},
+ { 0, 1, 6, 35}, { 0, 1, 6, 39},
+ { 0, 2, 6, 43}, { 0, 3, 6, 51},
+ { 0, 4, 6, 67}, { 0, 5, 6, 99},
+ { 0, 8, 6, 259}, { 32, 0, 4, 4},
+ { 48, 0, 4, 4}, { 16, 0, 4, 5},
+ { 32, 0, 5, 7}, { 32, 0, 5, 8},
+ { 32, 0, 5, 10}, { 32, 0, 5, 11},
+ { 0, 0, 6, 14}, { 0, 0, 6, 17},
+ { 0, 0, 6, 20}, { 0, 0, 6, 23},
+ { 0, 0, 6, 26}, { 0, 0, 6, 29},
+ { 0, 0, 6, 32}, { 0, 16, 6,65539},
+ { 0, 15, 6,32771}, { 0, 14, 6,16387},
+ { 0, 13, 6, 8195}, { 0, 12, 6, 4099},
+ { 0, 11, 6, 2051}, { 0, 10, 6, 1027},
+}; /* ML_defaultDTable */
+
+
+static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddBits)
+{
+ void* ptr = dt;
+ ZSTD_seqSymbol_header* const DTableH = (ZSTD_seqSymbol_header*)ptr;
+ ZSTD_seqSymbol* const cell = dt + 1;
+
+ DTableH->tableLog = 0;
+ DTableH->fastMode = 0;
+
+ cell->nbBits = 0;
+ cell->nextState = 0;
+ assert(nbAddBits < 255);
+ cell->nbAdditionalBits = (BYTE)nbAddBits;
+ cell->baseValue = baseValue;
+}
+
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * cannot fail if input is valid =>
+ * all inputs are presumed validated at this stage */
+void
+ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+ const short* normalizedCounter, unsigned maxSymbolValue,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ unsigned tableLog)
+{
+ ZSTD_seqSymbol* const tableDecode = dt+1;
+ U16 symbolNext[MaxSeq+1];
+
+ U32 const maxSV1 = maxSymbolValue + 1;
+ U32 const tableSize = 1 << tableLog;
+ U32 highThreshold = tableSize-1;
+
+ /* Sanity Checks */
+ assert(maxSymbolValue <= MaxSeq);
+ assert(tableLog <= MaxFSELog);
+
+ /* Init, lay down lowprob symbols */
+ { ZSTD_seqSymbol_header DTableH;
+ DTableH.tableLog = tableLog;
+ DTableH.fastMode = 1;
+ { S16 const largeLimit= (S16)(1 << (tableLog-1));
+ U32 s;
+ for (s=0; s<maxSV1; s++) {
+ if (normalizedCounter[s]==-1) {
+ tableDecode[highThreshold--].baseValue = s;
+ symbolNext[s] = 1;
+ } else {
+ if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+ symbolNext[s] = normalizedCounter[s];
+ } } }
+ memcpy(dt, &DTableH, sizeof(DTableH));
+ }
+
+ /* Spread symbols */
+ { U32 const tableMask = tableSize-1;
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 s, position = 0;
+ for (s=0; s<maxSV1; s++) {
+ int i;
+ for (i=0; i<normalizedCounter[s]; i++) {
+ tableDecode[position].baseValue = s;
+ position = (position + step) & tableMask;
+ while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
+ } }
+ assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+ }
+
+ /* Build Decoding table */
+ { U32 u;
+ for (u=0; u<tableSize; u++) {
+ U32 const symbol = tableDecode[u].baseValue;
+ U32 const nextState = symbolNext[symbol]++;
+ tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+ tableDecode[u].nextState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+ assert(nbAdditionalBits[symbol] < 255);
+ tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
+ tableDecode[u].baseValue = baseValue[symbol];
+ } }
+}
+
+
+/*! ZSTD_buildSeqTable() :
+ * @return : nb bytes read from src,
+ * or an error code if it fails */
+static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymbol** DTablePtr,
+ symbolEncodingType_e type, unsigned max, U32 maxLog,
+ const void* src, size_t srcSize,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable,
+ int ddictIsCold, int nbSeq)
+{
+ switch(type)
+ {
+ case set_rle :
+ if (!srcSize) return ERROR(srcSize_wrong);
+ if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected);
+ { U32 const symbol = *(const BYTE*)src;
+ U32 const baseline = baseValue[symbol];
+ U32 const nbBits = nbAdditionalBits[symbol];
+ ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
+ }
+ *DTablePtr = DTableSpace;
+ return 1;
+ case set_basic :
+ *DTablePtr = defaultTable;
+ return 0;
+ case set_repeat:
+ if (!flagRepeatTable) return ERROR(corruption_detected);
+ /* prefetch FSE table if used */
+ if (ddictIsCold && (nbSeq > 24 /* heuristic */)) {
+ const void* const pStart = *DTablePtr;
+ size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog));
+ PREFETCH_AREA(pStart, pSize);
+ }
+ return 0;
+ case set_compressed :
+ { unsigned tableLog;
+ S16 norm[MaxSeq+1];
+ size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
+ if (FSE_isError(headerSize)) return ERROR(corruption_detected);
+ if (tableLog > maxLog) return ERROR(corruption_detected);
+ ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
+ *DTablePtr = DTableSpace;
+ return headerSize;
+ }
+ default : /* impossible */
+ assert(0);
+ return ERROR(GENERIC);
+ }
+}
+
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+ const void* src, size_t srcSize)
+{
+ const BYTE* const istart = (const BYTE* const)src;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* ip = istart;
+ int nbSeq;
+ DEBUGLOG(5, "ZSTD_decodeSeqHeaders");
+
+ /* check */
+ if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong);
+
+ /* SeqHead */
+ nbSeq = *ip++;
+ if (!nbSeq) {
+ *nbSeqPtr=0;
+ if (srcSize != 1) return ERROR(srcSize_wrong);
+ return 1;
+ }
+ if (nbSeq > 0x7F) {
+ if (nbSeq == 0xFF) {
+ if (ip+2 > iend) return ERROR(srcSize_wrong);
+ nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
+ } else {
+ if (ip >= iend) return ERROR(srcSize_wrong);
+ nbSeq = ((nbSeq-0x80)<<8) + *ip++;
+ }
+ }
+ *nbSeqPtr = nbSeq;
+
+ /* FSE table descriptors */
+ if (ip+4 > iend) return ERROR(srcSize_wrong); /* minimum possible size */
+ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
+ symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
+ symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
+ ip++;
+
+ /* Build DTables */
+ { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
+ LLtype, MaxLL, LLFSELog,
+ ip, iend-ip,
+ LL_base, LL_bits,
+ LL_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);
+ ip += llhSize;
+ }
+
+ { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
+ OFtype, MaxOff, OffFSELog,
+ ip, iend-ip,
+ OF_base, OF_bits,
+ OF_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);
+ ip += ofhSize;
+ }
+
+ { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
+ MLtype, MaxML, MLFSELog,
+ ip, iend-ip,
+ ML_base, ML_bits,
+ ML_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected);
+ ip += mlhSize;
+ }
+ }
+
+ return ip-istart;
+}
+
+
+typedef struct {
+ size_t litLength;
+ size_t matchLength;
+ size_t offset;
+ const BYTE* match;
+} seq_t;
+
+typedef struct {
+ size_t state;
+ const ZSTD_seqSymbol* table;
+} ZSTD_fseState;
+
+typedef struct {
+ BIT_DStream_t DStream;
+ ZSTD_fseState stateLL;
+ ZSTD_fseState stateOffb;
+ ZSTD_fseState stateML;
+ size_t prevOffset[ZSTD_REP_NUM];
+ const BYTE* prefixStart;
+ const BYTE* dictEnd;
+ size_t pos;
+} seqState_t;
+
+
+/* ZSTD_execSequenceLast7():
+ * exceptional case : decompress a match starting within last 7 bytes of output buffer.
+ * requires more careful checks, to ensure there is no overflow.
+ * performance does not matter though.
+ * note : this case is supposed to be never generated "naturally" by reference encoder,
+ * since in most cases it needs at least 8 bytes to look for a match.
+ * but it's allowed by the specification. */
+FORCE_NOINLINE
+size_t ZSTD_execSequenceLast7(BYTE* op,
+ BYTE* const oend, seq_t sequence,
+ const BYTE** litPtr, const BYTE* const litLimit,
+ const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
+{
+ BYTE* const oLitEnd = op + sequence.litLength;
+ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+ BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE* match = oLitEnd - sequence.offset;
+
+ /* check */
+ if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must fit within dstBuffer */
+ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* try to read beyond literal buffer */
+
+ /* copy literals */
+ while (op < oLitEnd) *op++ = *(*litPtr)++;
+
+ /* copy Match */
+ if (sequence.offset > (size_t)(oLitEnd - base)) {
+ /* offset beyond prefix */
+ if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
+ match = dictEnd - (base-match);
+ if (match + sequence.matchLength <= dictEnd) {
+ memmove(oLitEnd, match, sequence.matchLength);
+ return sequenceLength;
+ }
+ /* span extDict & currentPrefixSegment */
+ { size_t const length1 = dictEnd - match;
+ memmove(oLitEnd, match, length1);
+ op = oLitEnd + length1;
+ sequence.matchLength -= length1;
+ match = base;
+ } }
+ while (op < oMatchEnd) *op++ = *match++;
+ return sequenceLength;
+}
+
+
+HINT_INLINE
+size_t ZSTD_execSequence(BYTE* op,
+ BYTE* const oend, seq_t sequence,
+ const BYTE** litPtr, const BYTE* const litLimit,
+ const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
+{
+ BYTE* const oLitEnd = op + sequence.litLength;
+ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+ BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
+ const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE* match = oLitEnd - sequence.offset;
+
+ /* check */
+ if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
+ if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
+
+ /* copy Literals */
+ ZSTD_copy8(op, *litPtr);
+ if (sequence.litLength > 8)
+ ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+ op = oLitEnd;
+ *litPtr = iLitEnd; /* update for next sequence */
+
+ /* copy Match */
+ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+ /* offset beyond prefix -> go into extDict */
+ if (sequence.offset > (size_t)(oLitEnd - virtualStart))
+ return ERROR(corruption_detected);
+ match = dictEnd + (match - prefixStart);
+ if (match + sequence.matchLength <= dictEnd) {
+ memmove(oLitEnd, match, sequence.matchLength);
+ return sequenceLength;
+ }
+ /* span extDict & currentPrefixSegment */
+ { size_t const length1 = dictEnd - match;
+ memmove(oLitEnd, match, length1);
+ op = oLitEnd + length1;
+ sequence.matchLength -= length1;
+ match = prefixStart;
+ if (op > oend_w || sequence.matchLength < MINMATCH) {
+ U32 i;
+ for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
+ return sequenceLength;
+ }
+ } }
+ /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
+
+ /* match within prefix */
+ if (sequence.offset < 8) {
+ /* close range match, overlap */
+ static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
+ static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
+ int const sub2 = dec64table[sequence.offset];
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += dec32table[sequence.offset];
+ ZSTD_copy4(op+4, match);
+ match -= sub2;
+ } else {
+ ZSTD_copy8(op, match);
+ }
+ op += 8; match += 8;
+
+ if (oMatchEnd > oend-(16-MINMATCH)) {
+ if (op < oend_w) {
+ ZSTD_wildcopy(op, match, oend_w - op);
+ match += oend_w - op;
+ op = oend_w;
+ }
+ while (op < oMatchEnd) *op++ = *match++;
+ } else {
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */
+ }
+ return sequenceLength;
+}
+
+
+HINT_INLINE
+size_t ZSTD_execSequenceLong(BYTE* op,
+ BYTE* const oend, seq_t sequence,
+ const BYTE** litPtr, const BYTE* const litLimit,
+ const BYTE* const prefixStart, const BYTE* const dictStart, const BYTE* const dictEnd)
+{
+ BYTE* const oLitEnd = op + sequence.litLength;
+ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+ BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
+ const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE* match = sequence.match;
+
+ /* check */
+ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
+ if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, dictStart, dictEnd);
+
+ /* copy Literals */
+ ZSTD_copy8(op, *litPtr); /* note : op <= oLitEnd <= oend_w == oend - 8 */
+ if (sequence.litLength > 8)
+ ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+ op = oLitEnd;
+ *litPtr = iLitEnd; /* update for next sequence */
+
+ /* copy Match */
+ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+ /* offset beyond prefix */
+ if (sequence.offset > (size_t)(oLitEnd - dictStart)) return ERROR(corruption_detected);
+ if (match + sequence.matchLength <= dictEnd) {
+ memmove(oLitEnd, match, sequence.matchLength);
+ return sequenceLength;
+ }
+ /* span extDict & currentPrefixSegment */
+ { size_t const length1 = dictEnd - match;
+ memmove(oLitEnd, match, length1);
+ op = oLitEnd + length1;
+ sequence.matchLength -= length1;
+ match = prefixStart;
+ if (op > oend_w || sequence.matchLength < MINMATCH) {
+ U32 i;
+ for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
+ return sequenceLength;
+ }
+ } }
+ assert(op <= oend_w);
+ assert(sequence.matchLength >= MINMATCH);
+
+ /* match within prefix */
+ if (sequence.offset < 8) {
+ /* close range match, overlap */
+ static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
+ static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
+ int const sub2 = dec64table[sequence.offset];
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += dec32table[sequence.offset];
+ ZSTD_copy4(op+4, match);
+ match -= sub2;
+ } else {
+ ZSTD_copy8(op, match);
+ }
+ op += 8; match += 8;
+
+ if (oMatchEnd > oend-(16-MINMATCH)) {
+ if (op < oend_w) {
+ ZSTD_wildcopy(op, match, oend_w - op);
+ match += oend_w - op;
+ op = oend_w;
+ }
+ while (op < oMatchEnd) *op++ = *match++;
+ } else {
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */
+ }
+ return sequenceLength;
+}
+
+static void
+ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt)
+{
+ const void* ptr = dt;
+ const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr;
+ DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+ DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits",
+ (U32)DStatePtr->state, DTableH->tableLog);
+ BIT_reloadDStream(bitD);
+ DStatePtr->table = dt + 1;
+}
+
+FORCE_INLINE_TEMPLATE void
+ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
+{
+ ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+ DStatePtr->state = DInfo.nextState + lowBits;
+}
+
+/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
+ * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
+ * bits before reloading. This value is the maximum number of bytes we read
+ * after reloading when we are decoding long offets.
+ */
+#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
+ (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
+ ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
+ : 0)
+
+typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+FORCE_INLINE_TEMPLATE seq_t
+ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
+{
+ seq_t seq;
+ U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
+ U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
+ U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
+ U32 const totalBits = llBits+mlBits+ofBits;
+ U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
+ U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
+ U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
+
+ /* sequence */
+ { size_t offset;
+ if (!ofBits)
+ offset = 0;
+ else {
+ ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
+ ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
+ assert(ofBits <= MaxOff);
+ if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) {
+ U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed);
+ offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
+ BIT_reloadDStream(&seqState->DStream);
+ if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+ assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */
+ } else {
+ offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+ }
+ }
+
+ if (ofBits <= 1) {
+ offset += (llBase==0);
+ if (offset) {
+ size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
+ if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset = temp;
+ } else { /* offset == 0 */
+ offset = seqState->prevOffset[0];
+ }
+ } else {
+ seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset;
+ }
+ seq.offset = offset;
+ }
+
+ seq.matchLength = mlBase
+ + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0); /* <= 16 bits */
+ if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
+ BIT_reloadDStream(&seqState->DStream);
+ if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
+ BIT_reloadDStream(&seqState->DStream);
+ /* Ensure there are enough bits to read the rest of data in 64-bit mode. */
+ ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
+
+ seq.litLength = llBase
+ + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0); /* <= 16 bits */
+ if (MEM_32bits())
+ BIT_reloadDStream(&seqState->DStream);
+
+ DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
+ (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
+
+ /* ANS state update */
+ ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
+ ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
+
+ return seq;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ const BYTE* ip = (const BYTE*)seqStart;
+ const BYTE* const iend = ip + seqSize;
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = ostart + maxDstSize;
+ BYTE* op = ostart;
+ const BYTE* litPtr = dctx->litPtr;
+ const BYTE* const litEnd = litPtr + dctx->litSize;
+ const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+ const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
+ const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+ DEBUGLOG(5, "ZSTD_decompressSequences_body");
+
+ /* Regen sequences */
+ if (nbSeq) {
+ seqState_t seqState;
+ dctx->fseEntropy = 1;
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+ ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+ ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+ ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+
+ for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
+ nbSeq--;
+ { seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
+ size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
+ DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
+ if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ op += oneSeqSize;
+ } }
+
+ /* check if reached exact end */
+ DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
+ if (nbSeq) return ERROR(corruption_detected);
+ /* save reps for next block */
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ }
+
+ /* last literal segment */
+ { size_t const lastLLSize = litEnd - litPtr;
+ if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+ memcpy(op, litPtr, lastLLSize);
+ op += lastLLSize;
+ }
+
+ return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+FORCE_INLINE_TEMPLATE seq_t
+ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
+{
+ seq_t seq;
+ U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
+ U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
+ U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
+ U32 const totalBits = llBits+mlBits+ofBits;
+ U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
+ U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
+ U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
+
+ /* sequence */
+ { size_t offset;
+ if (!ofBits)
+ offset = 0;
+ else {
+ ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
+ ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
+ assert(ofBits <= MaxOff);
+ if (MEM_32bits() && longOffsets) {
+ U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
+ offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
+ if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
+ if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+ } else {
+ offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+ }
+ }
+
+ if (ofBits <= 1) {
+ offset += (llBase==0);
+ if (offset) {
+ size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
+ if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset = temp;
+ } else {
+ offset = seqState->prevOffset[0];
+ }
+ } else {
+ seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset;
+ }
+ seq.offset = offset;
+ }
+
+ seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
+ if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
+ BIT_reloadDStream(&seqState->DStream);
+ if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
+ BIT_reloadDStream(&seqState->DStream);
+ /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
+ ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
+
+ seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
+ if (MEM_32bits())
+ BIT_reloadDStream(&seqState->DStream);
+
+ { size_t const pos = seqState->pos + seq.litLength;
+ const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
+ seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
+ * No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
+ seqState->pos = pos + seq.matchLength;
+ }
+
+ /* ANS state update */
+ ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
+ ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
+
+ return seq;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_decompressSequencesLong_body(
+ ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ const BYTE* ip = (const BYTE*)seqStart;
+ const BYTE* const iend = ip + seqSize;
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = ostart + maxDstSize;
+ BYTE* op = ostart;
+ const BYTE* litPtr = dctx->litPtr;
+ const BYTE* const litEnd = litPtr + dctx->litSize;
+ const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+ const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
+ const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+
+ /* Regen sequences */
+ if (nbSeq) {
+#define STORED_SEQS 4
+#define STORED_SEQS_MASK (STORED_SEQS-1)
+#define ADVANCED_SEQS 4
+ seq_t sequences[STORED_SEQS];
+ int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
+ seqState_t seqState;
+ int seqNb;
+ dctx->fseEntropy = 1;
+ { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+ seqState.prefixStart = prefixStart;
+ seqState.pos = (size_t)(op-prefixStart);
+ seqState.dictEnd = dictEnd;
+ assert(iend >= ip);
+ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+ ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+ ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+ ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+
+ /* prepare in advance */
+ for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
+ sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
+ PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ }
+ if (seqNb<seqAdvance) return ERROR(corruption_detected);
+
+ /* decode and decompress */
+ for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
+ seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
+ size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+ if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ sequences[seqNb & STORED_SEQS_MASK] = sequence;
+ op += oneSeqSize;
+ }
+ if (seqNb<nbSeq) return ERROR(corruption_detected);
+
+ /* finish queue */
+ seqNb -= seqAdvance;
+ for ( ; seqNb<nbSeq ; seqNb++) {
+ size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+ if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ op += oneSeqSize;
+ }
+
+ /* save reps for next block */
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ }
+
+ /* last literal segment */
+ { size_t const lastLLSize = litEnd - litPtr;
+ if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+ memcpy(op, litPtr, lastLLSize);
+ op += lastLLSize;
+ }
+
+ return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if DYNAMIC_BMI2
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+#endif /* DYNAMIC_BMI2 */
+
+typedef size_t (*ZSTD_decompressSequences_t)(
+ ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset);
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static size_t
+ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ DEBUGLOG(5, "ZSTD_decompressSequences");
+#if DYNAMIC_BMI2
+ if (dctx->bmi2) {
+ return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+ }
+#endif
+ return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+/* ZSTD_decompressSequencesLong() :
+ * decompression function triggered when a minimum share of offsets is considered "long",
+ * aka out of cache.
+ * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes mearning "farther than memory cache distance".
+ * This function will try to mitigate main memory latency through the use of prefetching */
+static size_t
+ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset)
+{
+ DEBUGLOG(5, "ZSTD_decompressSequencesLong");
+#if DYNAMIC_BMI2
+ if (dctx->bmi2) {
+ return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+ }
+#endif
+ return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+/* ZSTD_getLongOffsetsShare() :
+ * condition : offTable must be valid
+ * @return : "share" of long offsets (arbitrarily defined as > (1<<23))
+ * compared to maximum possible of (1<<OffFSELog) */
+static unsigned
+ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
+{
+ const void* ptr = offTable;
+ U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
+ const ZSTD_seqSymbol* table = offTable + 1;
+ U32 const max = 1 << tableLog;
+ U32 u, total = 0;
+ DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
+
+ assert(max <= (1 << OffFSELog)); /* max not too large */
+ for (u=0; u<max; u++) {
+ if (table[u].nbAdditionalBits > 22) total += 1;
+ }
+
+ assert(tableLog <= OffFSELog);
+ total <<= (OffFSELog - tableLog); /* scale to OffFSELog */
+
+ return total;
+}
+#endif
+
+
+size_t
+ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, const int frame)
+{ /* blockType == blockCompressed */
+ const BYTE* ip = (const BYTE*)src;
+ /* isLongOffset must be true if there are long offsets.
+ * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
+ * We don't expect that to be the case in 64-bit mode.
+ * In block mode, window size is not known, so we have to be conservative.
+ * (note: but it could be evaluated from current-lowLimit)
+ */
+ ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))));
+ DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
+
+ if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
+
+ /* Decode literals section */
+ { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
+ DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize);
+ if (ZSTD_isError(litCSize)) return litCSize;
+ ip += litCSize;
+ srcSize -= litCSize;
+ }
+
+ /* Build Decoding Tables */
+ {
+ /* These macros control at build-time which decompressor implementation
+ * we use. If neither is defined, we do some inspection and dispatch at
+ * runtime.
+ */
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ int usePrefetchDecoder = dctx->ddictIsCold;
+#endif
+ int nbSeq;
+ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize);
+ if (ZSTD_isError(seqHSize)) return seqHSize;
+ ip += seqHSize;
+ srcSize -= seqHSize;
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ if ( !usePrefetchDecoder
+ && (!frame || (dctx->fParams.windowSize > (1<<24)))
+ && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */
+ U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr);
+ U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */
+ usePrefetchDecoder = (shareLongOffsets >= minShare);
+ }
+#endif
+
+ dctx->ddictIsCold = 0;
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ if (usePrefetchDecoder)
+#endif
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+ return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
+#endif
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+ /* else */
+ return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
+#endif
+ }
+}
+
+
+size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ size_t dSize;
+ ZSTD_checkContinuity(dctx, dst);
+ dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
+ dctx->previousDstEnd = (char*)dst + dSize;
+ return dSize;
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h
new file mode 100644
index 000000000..7e9296041
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DEC_BLOCK_H
+#define ZSTD_DEC_BLOCK_H
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include <stddef.h> /* size_t */
+#include "zstd.h" /* DCtx, and some public functions */
+#include "zstd_internal.h" /* blockProperties_t, and some public functions */
+#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */
+
+
+/* === Prototypes === */
+
+/* note: prototypes already published within `zstd.h` :
+ * ZSTD_decompressBlock()
+ */
+
+/* note: prototypes already published within `zstd_internal.h` :
+ * ZSTD_getcBlockSize()
+ * ZSTD_decodeSeqHeaders()
+ */
+
+
+/* ZSTD_decompressBlock_internal() :
+ * decompress block, starting at `src`,
+ * into destination buffer `dst`.
+ * @return : decompressed block size,
+ * or an error code (which can be tested using ZSTD_isError())
+ */
+size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, const int frame);
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * this function must be called with valid parameters only
+ * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
+ * in which case it cannot fail.
+ * Internal use only.
+ */
+void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+ const short* normalizedCounter, unsigned maxSymbolValue,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ unsigned tableLog);
+
+
+#endif /* ZSTD_DEC_BLOCK_H */
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h b/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h
new file mode 100644
index 000000000..abd003051
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* zstd_decompress_internal:
+ * objects and definitions shared within lib/decompress modules */
+
+ #ifndef ZSTD_DECOMPRESS_INTERNAL_H
+ #define ZSTD_DECOMPRESS_INTERNAL_H
+
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include "mem.h" /* BYTE, U16, U32 */
+#include "zstd_internal.h" /* ZSTD_seqSymbol */
+
+
+
+/*-*******************************************************
+ * Constants
+ *********************************************************/
+static const U32 LL_base[MaxLL+1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 18, 20, 22, 24, 28, 32, 40,
+ 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
+ 0x2000, 0x4000, 0x8000, 0x10000 };
+
+static const U32 OF_base[MaxOff+1] = {
+ 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
+ 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
+ 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
+ 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
+
+static const U32 OF_bits[MaxOff+1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31 };
+
+static const U32 ML_base[MaxML+1] = {
+ 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 37, 39, 41, 43, 47, 51, 59,
+ 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
+ 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
+
+
+/*-*******************************************************
+ * Decompression types
+ *********************************************************/
+ typedef struct {
+ U32 fastMode;
+ U32 tableLog;
+ } ZSTD_seqSymbol_header;
+
+ typedef struct {
+ U16 nextState;
+ BYTE nbAdditionalBits;
+ BYTE nbBits;
+ U32 baseValue;
+ } ZSTD_seqSymbol;
+
+ #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log)))
+
+typedef struct {
+ ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
+ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
+ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
+ HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_entropyDTables_t;
+
+typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
+ ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
+ ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
+ ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
+
+typedef enum { zdss_init=0, zdss_loadHeader,
+ zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
+
+struct ZSTD_DCtx_s
+{
+ const ZSTD_seqSymbol* LLTptr;
+ const ZSTD_seqSymbol* MLTptr;
+ const ZSTD_seqSymbol* OFTptr;
+ const HUF_DTable* HUFptr;
+ ZSTD_entropyDTables_t entropy;
+ U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */
+ const void* previousDstEnd; /* detect continuity */
+ const void* prefixStart; /* start of current segment */
+ const void* virtualStart; /* virtual start of previous segment if it was just before current one */
+ const void* dictEnd; /* end of previous segment */
+ size_t expected;
+ ZSTD_frameHeader fParams;
+ U64 decodedSize;
+ blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
+ ZSTD_dStage stage;
+ U32 litEntropy;
+ U32 fseEntropy;
+ XXH64_state_t xxhState;
+ size_t headerSize;
+ ZSTD_format_e format;
+ const BYTE* litPtr;
+ ZSTD_customMem customMem;
+ size_t litSize;
+ size_t rleSize;
+ size_t staticSize;
+ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+
+ /* dictionary */
+ ZSTD_DDict* ddictLocal;
+ const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */
+ U32 dictID;
+ int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
+
+ /* streaming */
+ ZSTD_dStreamStage streamStage;
+ char* inBuff;
+ size_t inBuffSize;
+ size_t inPos;
+ size_t maxWindowSize;
+ char* outBuff;
+ size_t outBuffSize;
+ size_t outStart;
+ size_t outEnd;
+ size_t lhSize;
+ void* legacyContext;
+ U32 previousLegacyVersion;
+ U32 legacyVersion;
+ U32 hostageByte;
+ int noForwardProgress;
+
+ /* workspace */
+ BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
+ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
+}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
+
+
+/*-*******************************************************
+ * Shared internal functions
+ *********************************************************/
+
+/*! ZSTD_loadDEntropy() :
+ * dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of entropy tables read */
+size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+ const void* const dict, size_t const dictSize);
+
+/*! ZSTD_checkContinuity() :
+ * check if next `dst` follows previous position, where decompression ended.
+ * If yes, do nothing (continue on current segment).
+ * If not, classify previous segment as "external dictionary", and start a new segment.
+ * This function cannot fail. */
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
+
+
+#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff.h b/Utilities/cmzstd/lib/deprecated/zbuff.h
new file mode 100644
index 000000000..a93115da4
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* ***************************************************************
+* NOTES/WARNINGS
+******************************************************************/
+/* The streaming API defined here is deprecated.
+ * Consider migrating towards ZSTD_compressStream() API in `zstd.h`
+ * See 'lib/README.md'.
+ *****************************************************************/
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ZSTD_BUFFERED_H_23987
+#define ZSTD_BUFFERED_H_23987
+
+/* *************************************
+* Dependencies
+***************************************/
+#include <stddef.h> /* size_t */
+#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */
+
+
+/* ***************************************************************
+* Compiler specifics
+*****************************************************************/
+/* Deprecation warnings */
+/* Should these warnings be a problem,
+ it is generally possible to disable them,
+ typically with -Wno-deprecated-declarations for gcc
+ or _CRT_SECURE_NO_WARNINGS in Visual.
+ Otherwise, it's also possible to define ZBUFF_DISABLE_DEPRECATE_WARNINGS */
+#ifdef ZBUFF_DISABLE_DEPRECATE_WARNINGS
+# define ZBUFF_DEPRECATED(message) ZSTDLIB_API /* disable deprecation warnings */
+#else
+# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+# define ZBUFF_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API
+# elif (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__)
+# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message)))
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement ZBUFF_DEPRECATED for this compiler")
+# define ZBUFF_DEPRECATED(message) ZSTDLIB_API
+# endif
+#endif /* ZBUFF_DISABLE_DEPRECATE_WARNINGS */
+
+
+/* *************************************
+* Streaming functions
+***************************************/
+/* This is the easier "buffered" streaming API,
+* using an internal buffer to lift all restrictions on user-provided buffers
+* which can be any size, any place, for both input and output.
+* ZBUFF and ZSTD are 100% interoperable,
+* frames created by one can be decoded by the other one */
+
+typedef ZSTD_CStream ZBUFF_CCtx;
+ZBUFF_DEPRECATED("use ZSTD_createCStream") ZBUFF_CCtx* ZBUFF_createCCtx(void);
+ZBUFF_DEPRECATED("use ZSTD_freeCStream") size_t ZBUFF_freeCCtx(ZBUFF_CCtx* cctx);
+
+ZBUFF_DEPRECATED("use ZSTD_initCStream") size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel);
+ZBUFF_DEPRECATED("use ZSTD_initCStream_usingDict") size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
+
+ZBUFF_DEPRECATED("use ZSTD_compressStream") size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr);
+ZBUFF_DEPRECATED("use ZSTD_flushStream") size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr);
+ZBUFF_DEPRECATED("use ZSTD_endStream") size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr);
+
+/*-*************************************************
+* Streaming compression - howto
+*
+* A ZBUFF_CCtx object is required to track streaming operation.
+* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
+* ZBUFF_CCtx objects can be reused multiple times.
+*
+* Start by initializing ZBUF_CCtx.
+* Use ZBUFF_compressInit() to start a new compression operation.
+* Use ZBUFF_compressInitDictionary() for a compression which requires a dictionary.
+*
+* Use ZBUFF_compressContinue() repetitively to consume input stream.
+* *srcSizePtr and *dstCapacityPtr can be any size.
+* The function will report how many bytes were read or written within *srcSizePtr and *dstCapacityPtr.
+* Note that it may not consume the entire input, in which case it's up to the caller to present again remaining data.
+* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each call, so save its content if it matters or change @dst .
+* @return : a hint to preferred nb of bytes to use as input for next function call (it's just a hint, to improve latency)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush().
+* The nb of bytes written into `dst` will be reported into *dstCapacityPtr.
+* Note that the function cannot output more than *dstCapacityPtr,
+* therefore, some content might still be left into internal buffer if *dstCapacityPtr is too small.
+* @return : nb of bytes still present into internal buffer (0 if it's empty)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* ZBUFF_compressEnd() instructs to finish a frame.
+* It will perform a flush and write frame epilogue.
+* The epilogue is required for decoders to consider a frame completed.
+* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
+* In which case, call again ZBUFF_compressFlush() to complete the flush.
+* @return : nb of bytes still present into internal buffer (0 if it's empty)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* Hint : _recommended buffer_ sizes (not compulsory) : ZBUFF_recommendedCInSize() / ZBUFF_recommendedCOutSize()
+* input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, use this value to reduce intermediate stages (better latency)
+* output : ZBUFF_recommendedCOutSize==ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block. Skip some buffering.
+* By using both, it ensures that input will be entirely consumed, and output will always contain the result, reducing intermediate buffering.
+* **************************************************/
+
+
+typedef ZSTD_DStream ZBUFF_DCtx;
+ZBUFF_DEPRECATED("use ZSTD_createDStream") ZBUFF_DCtx* ZBUFF_createDCtx(void);
+ZBUFF_DEPRECATED("use ZSTD_freeDStream") size_t ZBUFF_freeDCtx(ZBUFF_DCtx* dctx);
+
+ZBUFF_DEPRECATED("use ZSTD_initDStream") size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx);
+ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* dctx, const void* dict, size_t dictSize);
+
+ZBUFF_DEPRECATED("use ZSTD_decompressStream") size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx,
+ void* dst, size_t* dstCapacityPtr,
+ const void* src, size_t* srcSizePtr);
+
+/*-***************************************************************************
+* Streaming decompression howto
+*
+* A ZBUFF_DCtx object is required to track streaming operations.
+* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
+* Use ZBUFF_decompressInit() to start a new decompression operation,
+* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary.
+* Note that ZBUFF_DCtx objects can be re-init multiple times.
+*
+* Use ZBUFF_decompressContinue() repetitively to consume your input.
+* *srcSizePtr and *dstCapacityPtr can be any size.
+* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
+* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
+* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`.
+* @return : 0 when a frame is completely decoded and fully flushed,
+* 1 when there is still some data left within internal buffer to flush,
+* >1 when more data is expected, with value being a suggested next input size (it's just a hint, which helps latency),
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize()
+* output : ZBUFF_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
+* input : ZBUFF_recommendedDInSize == 128KB + 3;
+* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
+* *******************************************************************************/
+
+
+/* *************************************
+* Tool functions
+***************************************/
+ZBUFF_DEPRECATED("use ZSTD_isError") unsigned ZBUFF_isError(size_t errorCode);
+ZBUFF_DEPRECATED("use ZSTD_getErrorName") const char* ZBUFF_getErrorName(size_t errorCode);
+
+/** Functions below provide recommended buffer sizes for Compression or Decompression operations.
+* These sizes are just hints, they tend to offer better latency */
+ZBUFF_DEPRECATED("use ZSTD_CStreamInSize") size_t ZBUFF_recommendedCInSize(void);
+ZBUFF_DEPRECATED("use ZSTD_CStreamOutSize") size_t ZBUFF_recommendedCOutSize(void);
+ZBUFF_DEPRECATED("use ZSTD_DStreamInSize") size_t ZBUFF_recommendedDInSize(void);
+ZBUFF_DEPRECATED("use ZSTD_DStreamOutSize") size_t ZBUFF_recommendedDOutSize(void);
+
+#endif /* ZSTD_BUFFERED_H_23987 */
+
+
+#ifdef ZBUFF_STATIC_LINKING_ONLY
+#ifndef ZBUFF_STATIC_H_30298098432
+#define ZBUFF_STATIC_H_30298098432
+
+/* ====================================================================================
+ * The definitions in this section are considered experimental.
+ * They should never be used in association with a dynamic library, as they may change in the future.
+ * They are provided for advanced usages.
+ * Use them only in association with static linking.
+ * ==================================================================================== */
+
+/*--- Dependency ---*/
+#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_customMem */
+#include "zstd.h"
+
+
+/*--- Custom memory allocator ---*/
+/*! ZBUFF_createCCtx_advanced() :
+ * Create a ZBUFF compression context using external alloc and free functions */
+ZBUFF_DEPRECATED("use ZSTD_createCStream_advanced") ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem);
+
+/*! ZBUFF_createDCtx_advanced() :
+ * Create a ZBUFF decompression context using external alloc and free functions */
+ZBUFF_DEPRECATED("use ZSTD_createDStream_advanced") ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem);
+
+
+/*--- Advanced Streaming Initialization ---*/
+ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize);
+
+
+#endif /* ZBUFF_STATIC_H_30298098432 */
+#endif /* ZBUFF_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_common.c b/Utilities/cmzstd/lib/deprecated/zbuff_common.c
new file mode 100644
index 000000000..661b9b0e1
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_common.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include "error_private.h"
+#include "zbuff.h"
+
+/*-****************************************
+* ZBUFF Error Management (deprecated)
+******************************************/
+
+/*! ZBUFF_isError() :
+* tells if a return value is an error code */
+unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); }
+/*! ZBUFF_getErrorName() :
+* provides error code string from function result (useful for debugging) */
+const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_compress.c b/Utilities/cmzstd/lib/deprecated/zbuff_compress.c
new file mode 100644
index 000000000..f39c60d89
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_compress.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/* *************************************
+* Dependencies
+***************************************/
+#define ZBUFF_STATIC_LINKING_ONLY
+#include "zbuff.h"
+
+
+/*-***********************************************************
+* Streaming compression
+*
+* A ZBUFF_CCtx object is required to track streaming operation.
+* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
+* Use ZBUFF_compressInit() to start a new compression operation.
+* ZBUFF_CCtx objects can be reused multiple times.
+*
+* Use ZBUFF_compressContinue() repetitively to consume your input.
+* *srcSizePtr and *dstCapacityPtr can be any size.
+* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
+* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input.
+* The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst .
+* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer.
+* Note that it will not output more than *dstCapacityPtr.
+* Therefore, some content might still be left into its internal buffer if dst buffer is too small.
+* @return : nb of bytes still present into internal buffer (0 if it's empty)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* ZBUFF_compressEnd() instructs to finish a frame.
+* It will perform a flush and write frame epilogue.
+* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
+* @return : nb of bytes still present into internal buffer (0 if it's empty)
+* or an error code, which can be tested using ZBUFF_isError().
+*
+* Hint : recommended buffer sizes (not compulsory)
+* input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value.
+* output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed.
+* ***********************************************************/
+
+ZBUFF_CCtx* ZBUFF_createCCtx(void)
+{
+ return ZSTD_createCStream();
+}
+
+ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem)
+{
+ return ZSTD_createCStream_advanced(customMem);
+}
+
+size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc)
+{
+ return ZSTD_freeCStream(zbc);
+}
+
+
+/* ====== Initialization ====== */
+
+size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+ if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */
+ return ZSTD_initCStream_advanced(zbc, dict, dictSize, params, pledgedSrcSize);
+}
+
+
+size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel)
+{
+ return ZSTD_initCStream_usingDict(zbc, dict, dictSize, compressionLevel);
+}
+
+size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel)
+{
+ return ZSTD_initCStream(zbc, compressionLevel);
+}
+
+/* ====== Compression ====== */
+
+
+size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc,
+ void* dst, size_t* dstCapacityPtr,
+ const void* src, size_t* srcSizePtr)
+{
+ size_t result;
+ ZSTD_outBuffer outBuff;
+ ZSTD_inBuffer inBuff;
+ outBuff.dst = dst;
+ outBuff.pos = 0;
+ outBuff.size = *dstCapacityPtr;
+ inBuff.src = src;
+ inBuff.pos = 0;
+ inBuff.size = *srcSizePtr;
+ result = ZSTD_compressStream(zbc, &outBuff, &inBuff);
+ *dstCapacityPtr = outBuff.pos;
+ *srcSizePtr = inBuff.pos;
+ return result;
+}
+
+
+
+/* ====== Finalize ====== */
+
+size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
+{
+ size_t result;
+ ZSTD_outBuffer outBuff;
+ outBuff.dst = dst;
+ outBuff.pos = 0;
+ outBuff.size = *dstCapacityPtr;
+ result = ZSTD_flushStream(zbc, &outBuff);
+ *dstCapacityPtr = outBuff.pos;
+ return result;
+}
+
+
+size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
+{
+ size_t result;
+ ZSTD_outBuffer outBuff;
+ outBuff.dst = dst;
+ outBuff.pos = 0;
+ outBuff.size = *dstCapacityPtr;
+ result = ZSTD_endStream(zbc, &outBuff);
+ *dstCapacityPtr = outBuff.pos;
+ return result;
+}
+
+
+
+/* *************************************
+* Tool functions
+***************************************/
+size_t ZBUFF_recommendedCInSize(void) { return ZSTD_CStreamInSize(); }
+size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_CStreamOutSize(); }
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c b/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c
new file mode 100644
index 000000000..923c22b73
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/* *************************************
+* Dependencies
+***************************************/
+#define ZBUFF_STATIC_LINKING_ONLY
+#include "zbuff.h"
+
+
+ZBUFF_DCtx* ZBUFF_createDCtx(void)
+{
+ return ZSTD_createDStream();
+}
+
+ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem)
+{
+ return ZSTD_createDStream_advanced(customMem);
+}
+
+size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd)
+{
+ return ZSTD_freeDStream(zbd);
+}
+
+
+/* *** Initialization *** */
+
+size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize)
+{
+ return ZSTD_initDStream_usingDict(zbd, dict, dictSize);
+}
+
+size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd)
+{
+ return ZSTD_initDStream(zbd);
+}
+
+
+/* *** Decompression *** */
+
+size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd,
+ void* dst, size_t* dstCapacityPtr,
+ const void* src, size_t* srcSizePtr)
+{
+ ZSTD_outBuffer outBuff;
+ ZSTD_inBuffer inBuff;
+ size_t result;
+ outBuff.dst = dst;
+ outBuff.pos = 0;
+ outBuff.size = *dstCapacityPtr;
+ inBuff.src = src;
+ inBuff.pos = 0;
+ inBuff.size = *srcSizePtr;
+ result = ZSTD_decompressStream(zbd, &outBuff, &inBuff);
+ *dstCapacityPtr = outBuff.pos;
+ *srcSizePtr = inBuff.pos;
+ return result;
+}
+
+
+/* *************************************
+* Tool functions
+***************************************/
+size_t ZBUFF_recommendedDInSize(void) { return ZSTD_DStreamInSize(); }
+size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_DStreamOutSize(); }
diff --git a/Utilities/cmzstd/lib/dictBuilder/cover.c b/Utilities/cmzstd/lib/dictBuilder/cover.c
new file mode 100644
index 000000000..b55bfb510
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/cover.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* *****************************************************************************
+ * Constructs a dictionary using a heuristic based on the following paper:
+ *
+ * Liao, Petri, Moffat, Wirth
+ * Effective Construction of Relative Lempel-Ziv Dictionaries
+ * Published in WWW 2016.
+ *
+ * Adapted from code originally written by @ot (Giuseppe Ottaviano).
+ ******************************************************************************/
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h> /* clock */
+
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "cover.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+/*-*************************************
+* Constants
+***************************************/
+#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
+#define DEFAULT_SPLITPOINT 1.0
+
+/*-*************************************
+* Console display
+***************************************/
+static int g_displayLevel = 2;
+#define DISPLAY(...) \
+ { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ }
+#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \
+ if (displayLevel >= l) { \
+ DISPLAY(__VA_ARGS__); \
+ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
+#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
+
+#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
+ if (displayLevel >= l) { \
+ if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \
+ g_time = clock(); \
+ DISPLAY(__VA_ARGS__); \
+ } \
+ }
+#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
+static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+
+/*-*************************************
+* Hash table
+***************************************
+* A small specialized hash map for storing activeDmers.
+* The map does not resize, so if it becomes full it will loop forever.
+* Thus, the map must be large enough to store every value.
+* The map implements linear probing and keeps its load less than 0.5.
+*/
+
+#define MAP_EMPTY_VALUE ((U32)-1)
+typedef struct COVER_map_pair_t_s {
+ U32 key;
+ U32 value;
+} COVER_map_pair_t;
+
+typedef struct COVER_map_s {
+ COVER_map_pair_t *data;
+ U32 sizeLog;
+ U32 size;
+ U32 sizeMask;
+} COVER_map_t;
+
+/**
+ * Clear the map.
+ */
+static void COVER_map_clear(COVER_map_t *map) {
+ memset(map->data, MAP_EMPTY_VALUE, map->size * sizeof(COVER_map_pair_t));
+}
+
+/**
+ * Initializes a map of the given size.
+ * Returns 1 on success and 0 on failure.
+ * The map must be destroyed with COVER_map_destroy().
+ * The map is only guaranteed to be large enough to hold size elements.
+ */
+static int COVER_map_init(COVER_map_t *map, U32 size) {
+ map->sizeLog = ZSTD_highbit32(size) + 2;
+ map->size = (U32)1 << map->sizeLog;
+ map->sizeMask = map->size - 1;
+ map->data = (COVER_map_pair_t *)malloc(map->size * sizeof(COVER_map_pair_t));
+ if (!map->data) {
+ map->sizeLog = 0;
+ map->size = 0;
+ return 0;
+ }
+ COVER_map_clear(map);
+ return 1;
+}
+
+/**
+ * Internal hash function
+ */
+static const U32 prime4bytes = 2654435761U;
+static U32 COVER_map_hash(COVER_map_t *map, U32 key) {
+ return (key * prime4bytes) >> (32 - map->sizeLog);
+}
+
+/**
+ * Helper function that returns the index that a key should be placed into.
+ */
+static U32 COVER_map_index(COVER_map_t *map, U32 key) {
+ const U32 hash = COVER_map_hash(map, key);
+ U32 i;
+ for (i = hash;; i = (i + 1) & map->sizeMask) {
+ COVER_map_pair_t *pos = &map->data[i];
+ if (pos->value == MAP_EMPTY_VALUE) {
+ return i;
+ }
+ if (pos->key == key) {
+ return i;
+ }
+ }
+}
+
+/**
+ * Returns the pointer to the value for key.
+ * If key is not in the map, it is inserted and the value is set to 0.
+ * The map must not be full.
+ */
+static U32 *COVER_map_at(COVER_map_t *map, U32 key) {
+ COVER_map_pair_t *pos = &map->data[COVER_map_index(map, key)];
+ if (pos->value == MAP_EMPTY_VALUE) {
+ pos->key = key;
+ pos->value = 0;
+ }
+ return &pos->value;
+}
+
+/**
+ * Deletes key from the map if present.
+ */
+static void COVER_map_remove(COVER_map_t *map, U32 key) {
+ U32 i = COVER_map_index(map, key);
+ COVER_map_pair_t *del = &map->data[i];
+ U32 shift = 1;
+ if (del->value == MAP_EMPTY_VALUE) {
+ return;
+ }
+ for (i = (i + 1) & map->sizeMask;; i = (i + 1) & map->sizeMask) {
+ COVER_map_pair_t *const pos = &map->data[i];
+ /* If the position is empty we are done */
+ if (pos->value == MAP_EMPTY_VALUE) {
+ del->value = MAP_EMPTY_VALUE;
+ return;
+ }
+ /* If pos can be moved to del do so */
+ if (((i - COVER_map_hash(map, pos->key)) & map->sizeMask) >= shift) {
+ del->key = pos->key;
+ del->value = pos->value;
+ del = pos;
+ shift = 1;
+ } else {
+ ++shift;
+ }
+ }
+}
+
+/**
+ * Destroys a map that is inited with COVER_map_init().
+ */
+static void COVER_map_destroy(COVER_map_t *map) {
+ if (map->data) {
+ free(map->data);
+ }
+ map->data = NULL;
+ map->size = 0;
+}
+
+/*-*************************************
+* Context
+***************************************/
+
+typedef struct {
+ const BYTE *samples;
+ size_t *offsets;
+ const size_t *samplesSizes;
+ size_t nbSamples;
+ size_t nbTrainSamples;
+ size_t nbTestSamples;
+ U32 *suffix;
+ size_t suffixSize;
+ U32 *freqs;
+ U32 *dmerAt;
+ unsigned d;
+} COVER_ctx_t;
+
+/* We need a global context for qsort... */
+static COVER_ctx_t *g_ctx = NULL;
+
+/*-*************************************
+* Helper functions
+***************************************/
+
+/**
+ * Returns the sum of the sample sizes.
+ */
+size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) {
+ size_t sum = 0;
+ unsigned i;
+ for (i = 0; i < nbSamples; ++i) {
+ sum += samplesSizes[i];
+ }
+ return sum;
+}
+
+/**
+ * Returns -1 if the dmer at lp is less than the dmer at rp.
+ * Return 0 if the dmers at lp and rp are equal.
+ * Returns 1 if the dmer at lp is greater than the dmer at rp.
+ */
+static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) {
+ U32 const lhs = *(U32 const *)lp;
+ U32 const rhs = *(U32 const *)rp;
+ return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d);
+}
+/**
+ * Faster version for d <= 8.
+ */
+static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
+ U64 const mask = (ctx->d == 8) ? (U64)-1 : (((U64)1 << (8 * ctx->d)) - 1);
+ U64 const lhs = MEM_readLE64(ctx->samples + *(U32 const *)lp) & mask;
+ U64 const rhs = MEM_readLE64(ctx->samples + *(U32 const *)rp) & mask;
+ if (lhs < rhs) {
+ return -1;
+ }
+ return (lhs > rhs);
+}
+
+/**
+ * Same as COVER_cmp() except ties are broken by pointer value
+ * NOTE: g_ctx must be set to call this function. A global is required because
+ * qsort doesn't take an opaque pointer.
+ */
+static int COVER_strict_cmp(const void *lp, const void *rp) {
+ int result = COVER_cmp(g_ctx, lp, rp);
+ if (result == 0) {
+ result = lp < rp ? -1 : 1;
+ }
+ return result;
+}
+/**
+ * Faster version for d <= 8.
+ */
+static int COVER_strict_cmp8(const void *lp, const void *rp) {
+ int result = COVER_cmp8(g_ctx, lp, rp);
+ if (result == 0) {
+ result = lp < rp ? -1 : 1;
+ }
+ return result;
+}
+
+/**
+ * Returns the first pointer in [first, last) whose element does not compare
+ * less than value. If no such element exists it returns last.
+ */
+static const size_t *COVER_lower_bound(const size_t *first, const size_t *last,
+ size_t value) {
+ size_t count = last - first;
+ while (count != 0) {
+ size_t step = count / 2;
+ const size_t *ptr = first;
+ ptr += step;
+ if (*ptr < value) {
+ first = ++ptr;
+ count -= step + 1;
+ } else {
+ count = step;
+ }
+ }
+ return first;
+}
+
+/**
+ * Generic groupBy function.
+ * Groups an array sorted by cmp into groups with equivalent values.
+ * Calls grp for each group.
+ */
+static void
+COVER_groupBy(const void *data, size_t count, size_t size, COVER_ctx_t *ctx,
+ int (*cmp)(COVER_ctx_t *, const void *, const void *),
+ void (*grp)(COVER_ctx_t *, const void *, const void *)) {
+ const BYTE *ptr = (const BYTE *)data;
+ size_t num = 0;
+ while (num < count) {
+ const BYTE *grpEnd = ptr + size;
+ ++num;
+ while (num < count && cmp(ctx, ptr, grpEnd) == 0) {
+ grpEnd += size;
+ ++num;
+ }
+ grp(ctx, ptr, grpEnd);
+ ptr = grpEnd;
+ }
+}
+
+/*-*************************************
+* Cover functions
+***************************************/
+
+/**
+ * Called on each group of positions with the same dmer.
+ * Counts the frequency of each dmer and saves it in the suffix array.
+ * Fills `ctx->dmerAt`.
+ */
+static void COVER_group(COVER_ctx_t *ctx, const void *group,
+ const void *groupEnd) {
+ /* The group consists of all the positions with the same first d bytes. */
+ const U32 *grpPtr = (const U32 *)group;
+ const U32 *grpEnd = (const U32 *)groupEnd;
+ /* The dmerId is how we will reference this dmer.
+ * This allows us to map the whole dmer space to a much smaller space, the
+ * size of the suffix array.
+ */
+ const U32 dmerId = (U32)(grpPtr - ctx->suffix);
+ /* Count the number of samples this dmer shows up in */
+ U32 freq = 0;
+ /* Details */
+ const size_t *curOffsetPtr = ctx->offsets;
+ const size_t *offsetsEnd = ctx->offsets + ctx->nbSamples;
+ /* Once *grpPtr >= curSampleEnd this occurrence of the dmer is in a
+ * different sample than the last.
+ */
+ size_t curSampleEnd = ctx->offsets[0];
+ for (; grpPtr != grpEnd; ++grpPtr) {
+ /* Save the dmerId for this position so we can get back to it. */
+ ctx->dmerAt[*grpPtr] = dmerId;
+ /* Dictionaries only help for the first reference to the dmer.
+ * After that zstd can reference the match from the previous reference.
+ * So only count each dmer once for each sample it is in.
+ */
+ if (*grpPtr < curSampleEnd) {
+ continue;
+ }
+ freq += 1;
+ /* Binary search to find the end of the sample *grpPtr is in.
+ * In the common case that grpPtr + 1 == grpEnd we can skip the binary
+ * search because the loop is over.
+ */
+ if (grpPtr + 1 != grpEnd) {
+ const size_t *sampleEndPtr =
+ COVER_lower_bound(curOffsetPtr, offsetsEnd, *grpPtr);
+ curSampleEnd = *sampleEndPtr;
+ curOffsetPtr = sampleEndPtr + 1;
+ }
+ }
+ /* At this point we are never going to look at this segment of the suffix
+ * array again. We take advantage of this fact to save memory.
+ * We store the frequency of the dmer in the first position of the group,
+ * which is dmerId.
+ */
+ ctx->suffix[dmerId] = freq;
+}
+
+
+/**
+ * Selects the best segment in an epoch.
+ * Segments of are scored according to the function:
+ *
+ * Let F(d) be the frequency of dmer d.
+ * Let S_i be the dmer at position i of segment S which has length k.
+ *
+ * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1})
+ *
+ * Once the dmer d is in the dictionay we set F(d) = 0.
+ */
+static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,
+ COVER_map_t *activeDmers, U32 begin,
+ U32 end,
+ ZDICT_cover_params_t parameters) {
+ /* Constants */
+ const U32 k = parameters.k;
+ const U32 d = parameters.d;
+ const U32 dmersInK = k - d + 1;
+ /* Try each segment (activeSegment) and save the best (bestSegment) */
+ COVER_segment_t bestSegment = {0, 0, 0};
+ COVER_segment_t activeSegment;
+ /* Reset the activeDmers in the segment */
+ COVER_map_clear(activeDmers);
+ /* The activeSegment starts at the beginning of the epoch. */
+ activeSegment.begin = begin;
+ activeSegment.end = begin;
+ activeSegment.score = 0;
+ /* Slide the activeSegment through the whole epoch.
+ * Save the best segment in bestSegment.
+ */
+ while (activeSegment.end < end) {
+ /* The dmerId for the dmer at the next position */
+ U32 newDmer = ctx->dmerAt[activeSegment.end];
+ /* The entry in activeDmers for this dmerId */
+ U32 *newDmerOcc = COVER_map_at(activeDmers, newDmer);
+ /* If the dmer isn't already present in the segment add its score. */
+ if (*newDmerOcc == 0) {
+ /* The paper suggest using the L-0.5 norm, but experiments show that it
+ * doesn't help.
+ */
+ activeSegment.score += freqs[newDmer];
+ }
+ /* Add the dmer to the segment */
+ activeSegment.end += 1;
+ *newDmerOcc += 1;
+
+ /* If the window is now too large, drop the first position */
+ if (activeSegment.end - activeSegment.begin == dmersInK + 1) {
+ U32 delDmer = ctx->dmerAt[activeSegment.begin];
+ U32 *delDmerOcc = COVER_map_at(activeDmers, delDmer);
+ activeSegment.begin += 1;
+ *delDmerOcc -= 1;
+ /* If this is the last occurence of the dmer, subtract its score */
+ if (*delDmerOcc == 0) {
+ COVER_map_remove(activeDmers, delDmer);
+ activeSegment.score -= freqs[delDmer];
+ }
+ }
+
+ /* If this segment is the best so far save it */
+ if (activeSegment.score > bestSegment.score) {
+ bestSegment = activeSegment;
+ }
+ }
+ {
+ /* Trim off the zero frequency head and tail from the segment. */
+ U32 newBegin = bestSegment.end;
+ U32 newEnd = bestSegment.begin;
+ U32 pos;
+ for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+ U32 freq = freqs[ctx->dmerAt[pos]];
+ if (freq != 0) {
+ newBegin = MIN(newBegin, pos);
+ newEnd = pos + 1;
+ }
+ }
+ bestSegment.begin = newBegin;
+ bestSegment.end = newEnd;
+ }
+ {
+ /* Zero out the frequency of each dmer covered by the chosen segment. */
+ U32 pos;
+ for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+ freqs[ctx->dmerAt[pos]] = 0;
+ }
+ }
+ return bestSegment;
+}
+
+/**
+ * Check the validity of the parameters.
+ * Returns non-zero if the parameters are valid and 0 otherwise.
+ */
+static int COVER_checkParameters(ZDICT_cover_params_t parameters,
+ size_t maxDictSize) {
+ /* k and d are required parameters */
+ if (parameters.d == 0 || parameters.k == 0) {
+ return 0;
+ }
+ /* k <= maxDictSize */
+ if (parameters.k > maxDictSize) {
+ return 0;
+ }
+ /* d <= k */
+ if (parameters.d > parameters.k) {
+ return 0;
+ }
+ /* 0 < splitPoint <= 1 */
+ if (parameters.splitPoint <= 0 || parameters.splitPoint > 1){
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * Clean up a context initialized with `COVER_ctx_init()`.
+ */
+static void COVER_ctx_destroy(COVER_ctx_t *ctx) {
+ if (!ctx) {
+ return;
+ }
+ if (ctx->suffix) {
+ free(ctx->suffix);
+ ctx->suffix = NULL;
+ }
+ if (ctx->freqs) {
+ free(ctx->freqs);
+ ctx->freqs = NULL;
+ }
+ if (ctx->dmerAt) {
+ free(ctx->dmerAt);
+ ctx->dmerAt = NULL;
+ }
+ if (ctx->offsets) {
+ free(ctx->offsets);
+ ctx->offsets = NULL;
+ }
+}
+
+/**
+ * Prepare a context for dictionary building.
+ * The context is only dependent on the parameter `d` and can used multiple
+ * times.
+ * Returns 1 on success or zero on error.
+ * The context must be destroyed with `COVER_ctx_destroy()`.
+ */
+static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
+ const size_t *samplesSizes, unsigned nbSamples,
+ unsigned d, double splitPoint) {
+ const BYTE *const samples = (const BYTE *)samplesBuffer;
+ const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
+ /* Split samples into testing and training sets */
+ const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples;
+ const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples;
+ const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize;
+ const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize;
+ /* Checks */
+ if (totalSamplesSize < MAX(d, sizeof(U64)) ||
+ totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
+ DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
+ (unsigned)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20));
+ return 0;
+ }
+ /* Check if there are at least 5 training samples */
+ if (nbTrainSamples < 5) {
+ DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid.", nbTrainSamples);
+ return 0;
+ }
+ /* Check if there's testing sample */
+ if (nbTestSamples < 1) {
+ DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.", nbTestSamples);
+ return 0;
+ }
+ /* Zero the context */
+ memset(ctx, 0, sizeof(*ctx));
+ DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples,
+ (unsigned)trainingSamplesSize);
+ DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples,
+ (unsigned)testSamplesSize);
+ ctx->samples = samples;
+ ctx->samplesSizes = samplesSizes;
+ ctx->nbSamples = nbSamples;
+ ctx->nbTrainSamples = nbTrainSamples;
+ ctx->nbTestSamples = nbTestSamples;
+ /* Partial suffix array */
+ ctx->suffixSize = trainingSamplesSize - MAX(d, sizeof(U64)) + 1;
+ ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+ /* Maps index to the dmerID */
+ ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+ /* The offsets of each file */
+ ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t));
+ if (!ctx->suffix || !ctx->dmerAt || !ctx->offsets) {
+ DISPLAYLEVEL(1, "Failed to allocate scratch buffers\n");
+ COVER_ctx_destroy(ctx);
+ return 0;
+ }
+ ctx->freqs = NULL;
+ ctx->d = d;
+
+ /* Fill offsets from the samplesSizes */
+ {
+ U32 i;
+ ctx->offsets[0] = 0;
+ for (i = 1; i <= nbSamples; ++i) {
+ ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1];
+ }
+ }
+ DISPLAYLEVEL(2, "Constructing partial suffix array\n");
+ {
+ /* suffix is a partial suffix array.
+ * It only sorts suffixes by their first parameters.d bytes.
+ * The sort is stable, so each dmer group is sorted by position in input.
+ */
+ U32 i;
+ for (i = 0; i < ctx->suffixSize; ++i) {
+ ctx->suffix[i] = i;
+ }
+ /* qsort doesn't take an opaque pointer, so pass as a global.
+ * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is.
+ */
+ g_ctx = ctx;
+#if defined(__OpenBSD__)
+ mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
+ (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
+#else
+ qsort(ctx->suffix, ctx->suffixSize, sizeof(U32),
+ (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
+#endif
+ }
+ DISPLAYLEVEL(2, "Computing frequencies\n");
+ /* For each dmer group (group of positions with the same first d bytes):
+ * 1. For each position we set dmerAt[position] = dmerID. The dmerID is
+ * (groupBeginPtr - suffix). This allows us to go from position to
+ * dmerID so we can look up values in freq.
+ * 2. We calculate how many samples the dmer occurs in and save it in
+ * freqs[dmerId].
+ */
+ COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx,
+ (ctx->d <= 8 ? &COVER_cmp8 : &COVER_cmp), &COVER_group);
+ ctx->freqs = ctx->suffix;
+ ctx->suffix = NULL;
+ return 1;
+}
+
+/**
+ * Given the prepared context build the dictionary.
+ */
+static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
+ COVER_map_t *activeDmers, void *dictBuffer,
+ size_t dictBufferCapacity,
+ ZDICT_cover_params_t parameters) {
+ BYTE *const dict = (BYTE *)dictBuffer;
+ size_t tail = dictBufferCapacity;
+ /* Divide the data up into epochs of equal size.
+ * We will select at least one segment from each epoch.
+ */
+ const unsigned epochs = MAX(1, (U32)(dictBufferCapacity / parameters.k / 4));
+ const unsigned epochSize = (U32)(ctx->suffixSize / epochs);
+ size_t epoch;
+ DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n",
+ epochs, epochSize);
+ /* Loop through the epochs until there are no more segments or the dictionary
+ * is full.
+ */
+ for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs) {
+ const U32 epochBegin = (U32)(epoch * epochSize);
+ const U32 epochEnd = epochBegin + epochSize;
+ size_t segmentSize;
+ /* Select a segment */
+ COVER_segment_t segment = COVER_selectSegment(
+ ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);
+ /* If the segment covers no dmers, then we are out of content */
+ if (segment.score == 0) {
+ break;
+ }
+ /* Trim the segment if necessary and if it is too small then we are done */
+ segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
+ if (segmentSize < parameters.d) {
+ break;
+ }
+ /* We fill the dictionary from the back to allow the best segments to be
+ * referenced with the smallest offsets.
+ */
+ tail -= segmentSize;
+ memcpy(dict + tail, ctx->samples + segment.begin, segmentSize);
+ DISPLAYUPDATE(
+ 2, "\r%u%% ",
+ (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));
+ }
+ DISPLAYLEVEL(2, "\r%79s\r", "");
+ return tail;
+}
+
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
+ void *dictBuffer, size_t dictBufferCapacity,
+ const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t parameters)
+{
+ BYTE* const dict = (BYTE*)dictBuffer;
+ COVER_ctx_t ctx;
+ COVER_map_t activeDmers;
+ parameters.splitPoint = 1.0;
+ /* Initialize global data */
+ g_displayLevel = parameters.zParams.notificationLevel;
+ /* Checks */
+ if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
+ DISPLAYLEVEL(1, "Cover parameters incorrect\n");
+ return ERROR(GENERIC);
+ }
+ if (nbSamples == 0) {
+ DISPLAYLEVEL(1, "Cover must have at least one input file\n");
+ return ERROR(GENERIC);
+ }
+ if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+ DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+ ZDICT_DICTSIZE_MIN);
+ return ERROR(dstSize_tooSmall);
+ }
+ /* Initialize context and activeDmers */
+ if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
+ parameters.d, parameters.splitPoint)) {
+ return ERROR(GENERIC);
+ }
+ if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {
+ DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");
+ COVER_ctx_destroy(&ctx);
+ return ERROR(GENERIC);
+ }
+
+ DISPLAYLEVEL(2, "Building dictionary\n");
+ {
+ const size_t tail =
+ COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer,
+ dictBufferCapacity, parameters);
+ const size_t dictionarySize = ZDICT_finalizeDictionary(
+ dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+ samplesBuffer, samplesSizes, nbSamples, parameters.zParams);
+ if (!ZSTD_isError(dictionarySize)) {
+ DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
+ (unsigned)dictionarySize);
+ }
+ COVER_ctx_destroy(&ctx);
+ COVER_map_destroy(&activeDmers);
+ return dictionarySize;
+ }
+}
+
+
+
+size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters,
+ const size_t *samplesSizes, const BYTE *samples,
+ size_t *offsets,
+ size_t nbTrainSamples, size_t nbSamples,
+ BYTE *const dict, size_t dictBufferCapacity) {
+ size_t totalCompressedSize = ERROR(GENERIC);
+ /* Pointers */
+ ZSTD_CCtx *cctx;
+ ZSTD_CDict *cdict;
+ void *dst;
+ /* Local variables */
+ size_t dstCapacity;
+ size_t i;
+ /* Allocate dst with enough space to compress the maximum sized sample */
+ {
+ size_t maxSampleSize = 0;
+ i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0;
+ for (; i < nbSamples; ++i) {
+ maxSampleSize = MAX(samplesSizes[i], maxSampleSize);
+ }
+ dstCapacity = ZSTD_compressBound(maxSampleSize);
+ dst = malloc(dstCapacity);
+ }
+ /* Create the cctx and cdict */
+ cctx = ZSTD_createCCtx();
+ cdict = ZSTD_createCDict(dict, dictBufferCapacity,
+ parameters.zParams.compressionLevel);
+ if (!dst || !cctx || !cdict) {
+ goto _compressCleanup;
+ }
+ /* Compress each sample and sum their sizes (or error) */
+ totalCompressedSize = dictBufferCapacity;
+ i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0;
+ for (; i < nbSamples; ++i) {
+ const size_t size = ZSTD_compress_usingCDict(
+ cctx, dst, dstCapacity, samples + offsets[i],
+ samplesSizes[i], cdict);
+ if (ZSTD_isError(size)) {
+ totalCompressedSize = ERROR(GENERIC);
+ goto _compressCleanup;
+ }
+ totalCompressedSize += size;
+ }
+_compressCleanup:
+ ZSTD_freeCCtx(cctx);
+ ZSTD_freeCDict(cdict);
+ if (dst) {
+ free(dst);
+ }
+ return totalCompressedSize;
+}
+
+
+/**
+ * Initialize the `COVER_best_t`.
+ */
+void COVER_best_init(COVER_best_t *best) {
+ if (best==NULL) return; /* compatible with init on NULL */
+ (void)ZSTD_pthread_mutex_init(&best->mutex, NULL);
+ (void)ZSTD_pthread_cond_init(&best->cond, NULL);
+ best->liveJobs = 0;
+ best->dict = NULL;
+ best->dictSize = 0;
+ best->compressedSize = (size_t)-1;
+ memset(&best->parameters, 0, sizeof(best->parameters));
+}
+
+/**
+ * Wait until liveJobs == 0.
+ */
+void COVER_best_wait(COVER_best_t *best) {
+ if (!best) {
+ return;
+ }
+ ZSTD_pthread_mutex_lock(&best->mutex);
+ while (best->liveJobs != 0) {
+ ZSTD_pthread_cond_wait(&best->cond, &best->mutex);
+ }
+ ZSTD_pthread_mutex_unlock(&best->mutex);
+}
+
+/**
+ * Call COVER_best_wait() and then destroy the COVER_best_t.
+ */
+void COVER_best_destroy(COVER_best_t *best) {
+ if (!best) {
+ return;
+ }
+ COVER_best_wait(best);
+ if (best->dict) {
+ free(best->dict);
+ }
+ ZSTD_pthread_mutex_destroy(&best->mutex);
+ ZSTD_pthread_cond_destroy(&best->cond);
+}
+
+/**
+ * Called when a thread is about to be launched.
+ * Increments liveJobs.
+ */
+void COVER_best_start(COVER_best_t *best) {
+ if (!best) {
+ return;
+ }
+ ZSTD_pthread_mutex_lock(&best->mutex);
+ ++best->liveJobs;
+ ZSTD_pthread_mutex_unlock(&best->mutex);
+}
+
+/**
+ * Called when a thread finishes executing, both on error or success.
+ * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
+ * If this dictionary is the best so far save it and its parameters.
+ */
+void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
+ ZDICT_cover_params_t parameters, void *dict,
+ size_t dictSize) {
+ if (!best) {
+ return;
+ }
+ {
+ size_t liveJobs;
+ ZSTD_pthread_mutex_lock(&best->mutex);
+ --best->liveJobs;
+ liveJobs = best->liveJobs;
+ /* If the new dictionary is better */
+ if (compressedSize < best->compressedSize) {
+ /* Allocate space if necessary */
+ if (!best->dict || best->dictSize < dictSize) {
+ if (best->dict) {
+ free(best->dict);
+ }
+ best->dict = malloc(dictSize);
+ if (!best->dict) {
+ best->compressedSize = ERROR(GENERIC);
+ best->dictSize = 0;
+ ZSTD_pthread_cond_signal(&best->cond);
+ ZSTD_pthread_mutex_unlock(&best->mutex);
+ return;
+ }
+ }
+ /* Save the dictionary, parameters, and size */
+ memcpy(best->dict, dict, dictSize);
+ best->dictSize = dictSize;
+ best->parameters = parameters;
+ best->compressedSize = compressedSize;
+ }
+ if (liveJobs == 0) {
+ ZSTD_pthread_cond_broadcast(&best->cond);
+ }
+ ZSTD_pthread_mutex_unlock(&best->mutex);
+ }
+}
+
+/**
+ * Parameters for COVER_tryParameters().
+ */
+typedef struct COVER_tryParameters_data_s {
+ const COVER_ctx_t *ctx;
+ COVER_best_t *best;
+ size_t dictBufferCapacity;
+ ZDICT_cover_params_t parameters;
+} COVER_tryParameters_data_t;
+
+/**
+ * Tries a set of parameters and updates the COVER_best_t with the results.
+ * This function is thread safe if zstd is compiled with multithreaded support.
+ * It takes its parameters as an *OWNING* opaque pointer to support threading.
+ */
+static void COVER_tryParameters(void *opaque) {
+ /* Save parameters as local variables */
+ COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;
+ const COVER_ctx_t *const ctx = data->ctx;
+ const ZDICT_cover_params_t parameters = data->parameters;
+ size_t dictBufferCapacity = data->dictBufferCapacity;
+ size_t totalCompressedSize = ERROR(GENERIC);
+ /* Allocate space for hash table, dict, and freqs */
+ COVER_map_t activeDmers;
+ BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+ U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+ if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {
+ DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");
+ goto _cleanup;
+ }
+ if (!dict || !freqs) {
+ DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");
+ goto _cleanup;
+ }
+ /* Copy the frequencies because we need to modify them */
+ memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32));
+ /* Build the dictionary */
+ {
+ const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,
+ dictBufferCapacity, parameters);
+ dictBufferCapacity = ZDICT_finalizeDictionary(
+ dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+ ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples,
+ parameters.zParams);
+ if (ZDICT_isError(dictBufferCapacity)) {
+ DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
+ goto _cleanup;
+ }
+ }
+ /* Check total compressed size */
+ totalCompressedSize = COVER_checkTotalCompressedSize(parameters, ctx->samplesSizes,
+ ctx->samples, ctx->offsets,
+ ctx->nbTrainSamples, ctx->nbSamples,
+ dict, dictBufferCapacity);
+
+_cleanup:
+ COVER_best_finish(data->best, totalCompressedSize, parameters, dict,
+ dictBufferCapacity);
+ free(data);
+ COVER_map_destroy(&activeDmers);
+ if (dict) {
+ free(dict);
+ }
+ if (freqs) {
+ free(freqs);
+ }
+}
+
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
+ void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
+ const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t *parameters) {
+ /* constants */
+ const unsigned nbThreads = parameters->nbThreads;
+ const double splitPoint =
+ parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+ const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
+ const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
+ const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
+ const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
+ const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
+ const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
+ const unsigned kIterations =
+ (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
+ /* Local variables */
+ const int displayLevel = parameters->zParams.notificationLevel;
+ unsigned iteration = 1;
+ unsigned d;
+ unsigned k;
+ COVER_best_t best;
+ POOL_ctx *pool = NULL;
+
+ /* Checks */
+ if (splitPoint <= 0 || splitPoint > 1) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
+ return ERROR(GENERIC);
+ }
+ if (kMinK < kMaxD || kMaxK < kMinK) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
+ return ERROR(GENERIC);
+ }
+ if (nbSamples == 0) {
+ DISPLAYLEVEL(1, "Cover must have at least one input file\n");
+ return ERROR(GENERIC);
+ }
+ if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+ DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+ ZDICT_DICTSIZE_MIN);
+ return ERROR(dstSize_tooSmall);
+ }
+ if (nbThreads > 1) {
+ pool = POOL_create(nbThreads, 1);
+ if (!pool) {
+ return ERROR(memory_allocation);
+ }
+ }
+ /* Initialization */
+ COVER_best_init(&best);
+ /* Turn down global display level to clean up display at level 2 and below */
+ g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
+ /* Loop through d first because each new value needs a new context */
+ LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
+ kIterations);
+ for (d = kMinD; d <= kMaxD; d += 2) {
+ /* Initialize the context for this value of d */
+ COVER_ctx_t ctx;
+ LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
+ if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint)) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return ERROR(GENERIC);
+ }
+ /* Loop through k reusing the same context */
+ for (k = kMinK; k <= kMaxK; k += kStepSize) {
+ /* Prepare the arguments */
+ COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc(
+ sizeof(COVER_tryParameters_data_t));
+ LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
+ if (!data) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
+ COVER_best_destroy(&best);
+ COVER_ctx_destroy(&ctx);
+ POOL_free(pool);
+ return ERROR(GENERIC);
+ }
+ data->ctx = &ctx;
+ data->best = &best;
+ data->dictBufferCapacity = dictBufferCapacity;
+ data->parameters = *parameters;
+ data->parameters.k = k;
+ data->parameters.d = d;
+ data->parameters.splitPoint = splitPoint;
+ data->parameters.steps = kSteps;
+ data->parameters.zParams.notificationLevel = g_displayLevel;
+ /* Check the parameters */
+ if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
+ DISPLAYLEVEL(1, "Cover parameters incorrect\n");
+ free(data);
+ continue;
+ }
+ /* Call the function and pass ownership of data to it */
+ COVER_best_start(&best);
+ if (pool) {
+ POOL_add(pool, &COVER_tryParameters, data);
+ } else {
+ COVER_tryParameters(data);
+ }
+ /* Print status */
+ LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ",
+ (unsigned)((iteration * 100) / kIterations));
+ ++iteration;
+ }
+ COVER_best_wait(&best);
+ COVER_ctx_destroy(&ctx);
+ }
+ LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
+ /* Fill the output buffer and parameters with output of the best parameters */
+ {
+ const size_t dictSize = best.dictSize;
+ if (ZSTD_isError(best.compressedSize)) {
+ const size_t compressedSize = best.compressedSize;
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return compressedSize;
+ }
+ *parameters = best.parameters;
+ memcpy(dictBuffer, best.dict, dictSize);
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return dictSize;
+ }
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/cover.h b/Utilities/cmzstd/lib/dictBuilder/cover.h
new file mode 100644
index 000000000..82e2e1cea
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/cover.h
@@ -0,0 +1,83 @@
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h> /* clock */
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+/**
+ * COVER_best_t is used for two purposes:
+ * 1. Synchronizing threads.
+ * 2. Saving the best parameters and dictionary.
+ *
+ * All of the methods except COVER_best_init() are thread safe if zstd is
+ * compiled with multithreaded support.
+ */
+typedef struct COVER_best_s {
+ ZSTD_pthread_mutex_t mutex;
+ ZSTD_pthread_cond_t cond;
+ size_t liveJobs;
+ void *dict;
+ size_t dictSize;
+ ZDICT_cover_params_t parameters;
+ size_t compressedSize;
+} COVER_best_t;
+
+/**
+ * A segment is a range in the source as well as the score of the segment.
+ */
+typedef struct {
+ U32 begin;
+ U32 end;
+ U32 score;
+} COVER_segment_t;
+
+/**
+ * Checks total compressed size of a dictionary
+ */
+size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters,
+ const size_t *samplesSizes, const BYTE *samples,
+ size_t *offsets,
+ size_t nbTrainSamples, size_t nbSamples,
+ BYTE *const dict, size_t dictBufferCapacity);
+
+/**
+ * Returns the sum of the sample sizes.
+ */
+size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) ;
+
+/**
+ * Initialize the `COVER_best_t`.
+ */
+void COVER_best_init(COVER_best_t *best);
+
+/**
+ * Wait until liveJobs == 0.
+ */
+void COVER_best_wait(COVER_best_t *best);
+
+/**
+ * Call COVER_best_wait() and then destroy the COVER_best_t.
+ */
+void COVER_best_destroy(COVER_best_t *best);
+
+/**
+ * Called when a thread is about to be launched.
+ * Increments liveJobs.
+ */
+void COVER_best_start(COVER_best_t *best);
+
+/**
+ * Called when a thread finishes executing, both on error or success.
+ * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
+ * If this dictionary is the best so far save it and its parameters.
+ */
+void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
+ ZDICT_cover_params_t parameters, void *dict,
+ size_t dictSize);
diff --git a/Utilities/cmzstd/lib/dictBuilder/divsufsort.c b/Utilities/cmzstd/lib/dictBuilder/divsufsort.c
new file mode 100644
index 000000000..ead922044
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/divsufsort.c
@@ -0,0 +1,1913 @@
+/*
+ * divsufsort.c for libdivsufsort-lite
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*- Compiler specifics -*/
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4244)
+# pragma warning(disable : 4127) /* C4127 : Condition expression is constant */
+#endif
+
+
+/*- Dependencies -*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "divsufsort.h"
+
+/*- Constants -*/
+#if defined(INLINE)
+# undef INLINE
+#endif
+#if !defined(INLINE)
+# define INLINE __inline
+#endif
+#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1)
+# undef ALPHABET_SIZE
+#endif
+#if !defined(ALPHABET_SIZE)
+# define ALPHABET_SIZE (256)
+#endif
+#define BUCKET_A_SIZE (ALPHABET_SIZE)
+#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE)
+#if defined(SS_INSERTIONSORT_THRESHOLD)
+# if SS_INSERTIONSORT_THRESHOLD < 1
+# undef SS_INSERTIONSORT_THRESHOLD
+# define SS_INSERTIONSORT_THRESHOLD (1)
+# endif
+#else
+# define SS_INSERTIONSORT_THRESHOLD (8)
+#endif
+#if defined(SS_BLOCKSIZE)
+# if SS_BLOCKSIZE < 0
+# undef SS_BLOCKSIZE
+# define SS_BLOCKSIZE (0)
+# elif 32768 <= SS_BLOCKSIZE
+# undef SS_BLOCKSIZE
+# define SS_BLOCKSIZE (32767)
+# endif
+#else
+# define SS_BLOCKSIZE (1024)
+#endif
+/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */
+#if SS_BLOCKSIZE == 0
+# define SS_MISORT_STACKSIZE (96)
+#elif SS_BLOCKSIZE <= 4096
+# define SS_MISORT_STACKSIZE (16)
+#else
+# define SS_MISORT_STACKSIZE (24)
+#endif
+#define SS_SMERGE_STACKSIZE (32)
+#define TR_INSERTIONSORT_THRESHOLD (8)
+#define TR_STACKSIZE (64)
+
+
+/*- Macros -*/
+#ifndef SWAP
+# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0)
+#endif /* SWAP */
+#ifndef MIN
+# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif /* MIN */
+#ifndef MAX
+# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif /* MAX */
+#define STACK_PUSH(_a, _b, _c, _d)\
+ do {\
+ assert(ssize < STACK_SIZE);\
+ stack[ssize].a = (_a), stack[ssize].b = (_b),\
+ stack[ssize].c = (_c), stack[ssize++].d = (_d);\
+ } while(0)
+#define STACK_PUSH5(_a, _b, _c, _d, _e)\
+ do {\
+ assert(ssize < STACK_SIZE);\
+ stack[ssize].a = (_a), stack[ssize].b = (_b),\
+ stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\
+ } while(0)
+#define STACK_POP(_a, _b, _c, _d)\
+ do {\
+ assert(0 <= ssize);\
+ if(ssize == 0) { return; }\
+ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+ (_c) = stack[ssize].c, (_d) = stack[ssize].d;\
+ } while(0)
+#define STACK_POP5(_a, _b, _c, _d, _e)\
+ do {\
+ assert(0 <= ssize);\
+ if(ssize == 0) { return; }\
+ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+ (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\
+ } while(0)
+#define BUCKET_A(_c0) bucket_A[(_c0)]
+#if ALPHABET_SIZE == 256
+#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)])
+#else
+#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)])
+#endif
+
+
+/*- Private Functions -*/
+
+static const int lg_table[256]= {
+ -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+int
+ss_ilg(int n) {
+#if SS_BLOCKSIZE == 0
+ return (n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]);
+#elif SS_BLOCKSIZE < 256
+ return lg_table[n];
+#else
+ return (n & 0xff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff];
+#endif
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+#if SS_BLOCKSIZE != 0
+
+static const int sqq_table[256] = {
+ 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61,
+ 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89,
+ 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109,
+110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,
+156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
+169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,
+181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,
+192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,
+202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
+212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,
+221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,
+230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
+239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
+247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
+};
+
+static INLINE
+int
+ss_isqrt(int x) {
+ int y, e;
+
+ if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }
+ e = (x & 0xffff0000) ?
+ ((x & 0xff000000) ?
+ 24 + lg_table[(x >> 24) & 0xff] :
+ 16 + lg_table[(x >> 16) & 0xff]) :
+ ((x & 0x0000ff00) ?
+ 8 + lg_table[(x >> 8) & 0xff] :
+ 0 + lg_table[(x >> 0) & 0xff]);
+
+ if(e >= 16) {
+ y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);
+ if(e >= 24) { y = (y + 1 + x / y) >> 1; }
+ y = (y + 1 + x / y) >> 1;
+ } else if(e >= 8) {
+ y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;
+ } else {
+ return sqq_table[x] >> 4;
+ }
+
+ return (x < (y * y)) ? y - 1 : y;
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Compares two suffixes. */
+static INLINE
+int
+ss_compare(const unsigned char *T,
+ const int *p1, const int *p2,
+ int depth) {
+ const unsigned char *U1, *U2, *U1n, *U2n;
+
+ for(U1 = T + depth + *p1,
+ U2 = T + depth + *p2,
+ U1n = T + *(p1 + 1) + 2,
+ U2n = T + *(p2 + 1) + 2;
+ (U1 < U1n) && (U2 < U2n) && (*U1 == *U2);
+ ++U1, ++U2) {
+ }
+
+ return U1 < U1n ?
+ (U2 < U2n ? *U1 - *U2 : 1) :
+ (U2 < U2n ? -1 : 0);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)
+
+/* Insertionsort for small size groups */
+static
+void
+ss_insertionsort(const unsigned char *T, const int *PA,
+ int *first, int *last, int depth) {
+ int *i, *j;
+ int t;
+ int r;
+
+ for(i = last - 2; first <= i; --i) {
+ for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {
+ do { *(j - 1) = *j; } while((++j < last) && (*j < 0));
+ if(last <= j) { break; }
+ }
+ if(r == 0) { *j = ~*j; }
+ *(j - 1) = t;
+ }
+}
+
+#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+void
+ss_fixdown(const unsigned char *Td, const int *PA,
+ int *SA, int i, int size) {
+ int j, k;
+ int v;
+ int c, d, e;
+
+ for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+ d = Td[PA[SA[k = j++]]];
+ if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }
+ if(d <= c) { break; }
+ }
+ SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) {
+ int i, m;
+ int t;
+
+ m = size;
+ if((size % 2) == 0) {
+ m--;
+ if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }
+ }
+
+ for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }
+ if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }
+ for(i = m - 1; 0 < i; --i) {
+ t = SA[0], SA[0] = SA[i];
+ ss_fixdown(Td, PA, SA, 0, i);
+ SA[i] = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+int *
+ss_median3(const unsigned char *Td, const int *PA,
+ int *v1, int *v2, int *v3) {
+ int *t;
+ if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }
+ if(Td[PA[*v2]] > Td[PA[*v3]]) {
+ if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }
+ else { return v3; }
+ }
+ return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+int *
+ss_median5(const unsigned char *Td, const int *PA,
+ int *v1, int *v2, int *v3, int *v4, int *v5) {
+ int *t;
+ if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }
+ if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }
+ if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }
+ if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }
+ if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }
+ if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }
+ return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+int *
+ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) {
+ int *middle;
+ int t;
+
+ t = last - first;
+ middle = first + t / 2;
+
+ if(t <= 512) {
+ if(t <= 32) {
+ return ss_median3(Td, PA, first, middle, last - 1);
+ } else {
+ t >>= 2;
+ return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);
+ }
+ }
+ t >>= 3;
+ first = ss_median3(Td, PA, first, first + t, first + (t << 1));
+ middle = ss_median3(Td, PA, middle - t, middle, middle + t);
+ last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);
+ return ss_median3(Td, PA, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Binary partition for substrings. */
+static INLINE
+int *
+ss_partition(const int *PA,
+ int *first, int *last, int depth) {
+ int *a, *b;
+ int t;
+ for(a = first - 1, b = last;;) {
+ for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }
+ for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { }
+ if(b <= a) { break; }
+ t = ~*b;
+ *b = *a;
+ *a = t;
+ }
+ if(first < a) { *first = ~*first; }
+ return a;
+}
+
+/* Multikey introsort for medium size groups. */
+static
+void
+ss_mintrosort(const unsigned char *T, const int *PA,
+ int *first, int *last,
+ int depth) {
+#define STACK_SIZE SS_MISORT_STACKSIZE
+ struct { int *a, *b, c; int d; } stack[STACK_SIZE];
+ const unsigned char *Td;
+ int *a, *b, *c, *d, *e, *f;
+ int s, t;
+ int ssize;
+ int limit;
+ int v, x = 0;
+
+ for(ssize = 0, limit = ss_ilg(last - first);;) {
+
+ if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {
+#if 1 < SS_INSERTIONSORT_THRESHOLD
+ if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }
+#endif
+ STACK_POP(first, last, depth, limit);
+ continue;
+ }
+
+ Td = T + depth;
+ if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }
+ if(limit < 0) {
+ for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {
+ if((x = Td[PA[*a]]) != v) {
+ if(1 < (a - first)) { break; }
+ v = x;
+ first = a;
+ }
+ }
+ if(Td[PA[*first] - 1] < v) {
+ first = ss_partition(PA, first, a, depth);
+ }
+ if((a - first) <= (last - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH(a, last, depth, -1);
+ last = a, depth += 1, limit = ss_ilg(a - first);
+ } else {
+ first = a, limit = -1;
+ }
+ } else {
+ if(1 < (last - a)) {
+ STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));
+ first = a, limit = -1;
+ } else {
+ last = a, depth += 1, limit = ss_ilg(a - first);
+ }
+ }
+ continue;
+ }
+
+ /* choose pivot */
+ a = ss_pivot(Td, PA, first, last);
+ v = Td[PA[*a]];
+ SWAP(*first, *a);
+
+ /* partition */
+ for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }
+ if(((a = b) < last) && (x < v)) {
+ for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ }
+ for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }
+ if((b < (d = c)) && (x > v)) {
+ for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+ for(; b < c;) {
+ SWAP(*b, *c);
+ for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+
+ if(a <= d) {
+ c = b - 1;
+
+ if((s = a - first) > (t = b - a)) { s = t; }
+ for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ if((s = d - c) > (t = last - d - 1)) { s = t; }
+ for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+
+ a = first + (b - a), c = last - (d - c);
+ b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);
+
+ if((a - first) <= (last - c)) {
+ if((last - c) <= (c - b)) {
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ STACK_PUSH(c, last, depth, limit);
+ last = a;
+ } else if((a - first) <= (c - b)) {
+ STACK_PUSH(c, last, depth, limit);
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ last = a;
+ } else {
+ STACK_PUSH(c, last, depth, limit);
+ STACK_PUSH(first, a, depth, limit);
+ first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+ }
+ } else {
+ if((a - first) <= (c - b)) {
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ STACK_PUSH(first, a, depth, limit);
+ first = c;
+ } else if((last - c) <= (c - b)) {
+ STACK_PUSH(first, a, depth, limit);
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ first = c;
+ } else {
+ STACK_PUSH(first, a, depth, limit);
+ STACK_PUSH(c, last, depth, limit);
+ first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+ }
+ }
+ } else {
+ limit += 1;
+ if(Td[PA[*first] - 1] < v) {
+ first = ss_partition(PA, first, last, depth);
+ limit = ss_ilg(last - first);
+ }
+ depth += 1;
+ }
+ }
+#undef STACK_SIZE
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if SS_BLOCKSIZE != 0
+
+static INLINE
+void
+ss_blockswap(int *a, int *b, int n) {
+ int t;
+ for(; 0 < n; --n, ++a, ++b) {
+ t = *a, *a = *b, *b = t;
+ }
+}
+
+static INLINE
+void
+ss_rotate(int *first, int *middle, int *last) {
+ int *a, *b, t;
+ int l, r;
+ l = middle - first, r = last - middle;
+ for(; (0 < l) && (0 < r);) {
+ if(l == r) { ss_blockswap(first, middle, l); break; }
+ if(l < r) {
+ a = last - 1, b = middle - 1;
+ t = *a;
+ do {
+ *a-- = *b, *b-- = *a;
+ if(b < first) {
+ *a = t;
+ last = a;
+ if((r -= l + 1) <= l) { break; }
+ a -= 1, b = middle - 1;
+ t = *a;
+ }
+ } while(1);
+ } else {
+ a = first, b = middle;
+ t = *a;
+ do {
+ *a++ = *b, *b++ = *a;
+ if(last <= b) {
+ *a = t;
+ first = a + 1;
+ if((l -= r + 1) <= r) { break; }
+ a += 1, b = middle;
+ t = *a;
+ }
+ } while(1);
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static
+void
+ss_inplacemerge(const unsigned char *T, const int *PA,
+ int *first, int *middle, int *last,
+ int depth) {
+ const int *p;
+ int *a, *b;
+ int len, half;
+ int q, r;
+ int x;
+
+ for(;;) {
+ if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }
+ else { x = 0; p = PA + *(last - 1); }
+ for(a = first, len = middle - first, half = len >> 1, r = -1;
+ 0 < len;
+ len = half, half >>= 1) {
+ b = a + half;
+ q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);
+ if(q < 0) {
+ a = b + 1;
+ half -= (len & 1) ^ 1;
+ } else {
+ r = q;
+ }
+ }
+ if(a < middle) {
+ if(r == 0) { *a = ~*a; }
+ ss_rotate(a, middle, last);
+ last -= middle - a;
+ middle = a;
+ if(first == middle) { break; }
+ }
+ --last;
+ if(x != 0) { while(*--last < 0) { } }
+ if(middle == last) { break; }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Merge-forward with internal buffer. */
+static
+void
+ss_mergeforward(const unsigned char *T, const int *PA,
+ int *first, int *middle, int *last,
+ int *buf, int depth) {
+ int *a, *b, *c, *bufend;
+ int t;
+ int r;
+
+ bufend = buf + (middle - first) - 1;
+ ss_blockswap(buf, first, middle - first);
+
+ for(t = *(a = first), b = buf, c = middle;;) {
+ r = ss_compare(T, PA + *b, PA + *c, depth);
+ if(r < 0) {
+ do {
+ *a++ = *b;
+ if(bufend <= b) { *bufend = t; return; }
+ *b++ = *a;
+ } while(*b < 0);
+ } else if(r > 0) {
+ do {
+ *a++ = *c, *c++ = *a;
+ if(last <= c) {
+ while(b < bufend) { *a++ = *b, *b++ = *a; }
+ *a = *b, *b = t;
+ return;
+ }
+ } while(*c < 0);
+ } else {
+ *c = ~*c;
+ do {
+ *a++ = *b;
+ if(bufend <= b) { *bufend = t; return; }
+ *b++ = *a;
+ } while(*b < 0);
+
+ do {
+ *a++ = *c, *c++ = *a;
+ if(last <= c) {
+ while(b < bufend) { *a++ = *b, *b++ = *a; }
+ *a = *b, *b = t;
+ return;
+ }
+ } while(*c < 0);
+ }
+ }
+}
+
+/* Merge-backward with internal buffer. */
+static
+void
+ss_mergebackward(const unsigned char *T, const int *PA,
+ int *first, int *middle, int *last,
+ int *buf, int depth) {
+ const int *p1, *p2;
+ int *a, *b, *c, *bufend;
+ int t;
+ int r;
+ int x;
+
+ bufend = buf + (last - middle) - 1;
+ ss_blockswap(buf, middle, last - middle);
+
+ x = 0;
+ if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; }
+ else { p1 = PA + *bufend; }
+ if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }
+ else { p2 = PA + *(middle - 1); }
+ for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {
+ r = ss_compare(T, p1, p2, depth);
+ if(0 < r) {
+ if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+ *a-- = *b;
+ if(b <= buf) { *buf = t; break; }
+ *b-- = *a;
+ if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+ else { p1 = PA + *b; }
+ } else if(r < 0) {
+ if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+ *a-- = *c, *c-- = *a;
+ if(c < first) {
+ while(buf < b) { *a-- = *b, *b-- = *a; }
+ *a = *b, *b = t;
+ break;
+ }
+ if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+ else { p2 = PA + *c; }
+ } else {
+ if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+ *a-- = ~*b;
+ if(b <= buf) { *buf = t; break; }
+ *b-- = *a;
+ if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+ *a-- = *c, *c-- = *a;
+ if(c < first) {
+ while(buf < b) { *a-- = *b, *b-- = *a; }
+ *a = *b, *b = t;
+ break;
+ }
+ if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+ else { p1 = PA + *b; }
+ if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+ else { p2 = PA + *c; }
+ }
+ }
+}
+
+/* D&C based merge. */
+static
+void
+ss_swapmerge(const unsigned char *T, const int *PA,
+ int *first, int *middle, int *last,
+ int *buf, int bufsize, int depth) {
+#define STACK_SIZE SS_SMERGE_STACKSIZE
+#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))
+#define MERGE_CHECK(a, b, c)\
+ do {\
+ if(((c) & 1) ||\
+ (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\
+ *(a) = ~*(a);\
+ }\
+ if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\
+ *(b) = ~*(b);\
+ }\
+ } while(0)
+ struct { int *a, *b, *c; int d; } stack[STACK_SIZE];
+ int *l, *r, *lm, *rm;
+ int m, len, half;
+ int ssize;
+ int check, next;
+
+ for(check = 0, ssize = 0;;) {
+ if((last - middle) <= bufsize) {
+ if((first < middle) && (middle < last)) {
+ ss_mergebackward(T, PA, first, middle, last, buf, depth);
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ continue;
+ }
+
+ if((middle - first) <= bufsize) {
+ if(first < middle) {
+ ss_mergeforward(T, PA, first, middle, last, buf, depth);
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ continue;
+ }
+
+ for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;
+ 0 < len;
+ len = half, half >>= 1) {
+ if(ss_compare(T, PA + GETIDX(*(middle + m + half)),
+ PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {
+ m += half + 1;
+ half -= (len & 1) ^ 1;
+ }
+ }
+
+ if(0 < m) {
+ lm = middle - m, rm = middle + m;
+ ss_blockswap(lm, middle, m);
+ l = r = middle, next = 0;
+ if(rm < last) {
+ if(*rm < 0) {
+ *rm = ~*rm;
+ if(first < lm) { for(; *--l < 0;) { } next |= 4; }
+ next |= 1;
+ } else if(first < lm) {
+ for(; *r < 0; ++r) { }
+ next |= 2;
+ }
+ }
+
+ if((l - first) <= (last - r)) {
+ STACK_PUSH(r, rm, last, (next & 3) | (check & 4));
+ middle = lm, last = l, check = (check & 3) | (next & 4);
+ } else {
+ if((next & 2) && (r == middle)) { next ^= 6; }
+ STACK_PUSH(first, lm, l, (check & 3) | (next & 4));
+ first = r, middle = rm, check = (next & 3) | (check & 4);
+ }
+ } else {
+ if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {
+ *middle = ~*middle;
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ }
+ }
+#undef STACK_SIZE
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Substring sort */
+static
+void
+sssort(const unsigned char *T, const int *PA,
+ int *first, int *last,
+ int *buf, int bufsize,
+ int depth, int n, int lastsuffix) {
+ int *a;
+#if SS_BLOCKSIZE != 0
+ int *b, *middle, *curbuf;
+ int j, k, curbufsize, limit;
+#endif
+ int i;
+
+ if(lastsuffix != 0) { ++first; }
+
+#if SS_BLOCKSIZE == 0
+ ss_mintrosort(T, PA, first, last, depth);
+#else
+ if((bufsize < SS_BLOCKSIZE) &&
+ (bufsize < (last - first)) &&
+ (bufsize < (limit = ss_isqrt(last - first)))) {
+ if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }
+ buf = middle = last - limit, bufsize = limit;
+ } else {
+ middle = last, limit = 0;
+ }
+ for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#endif
+ curbufsize = last - (a + SS_BLOCKSIZE);
+ curbuf = a + SS_BLOCKSIZE;
+ if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }
+ for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {
+ ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);
+ }
+ }
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, a, middle, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, a, middle, depth);
+#endif
+ for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {
+ if(i & 1) {
+ ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);
+ a -= k;
+ }
+ }
+ if(limit != 0) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, middle, last, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, middle, last, depth);
+#endif
+ ss_inplacemerge(T, PA, first, middle, last, depth);
+ }
+#endif
+
+ if(lastsuffix != 0) {
+ /* Insert last type B* suffix. */
+ int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;
+ for(a = first, i = *(first - 1);
+ (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));
+ ++a) {
+ *(a - 1) = *a;
+ }
+ *(a - 1) = i;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+int
+tr_ilg(int n) {
+ return (n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Simple insertionsort for small size groups. */
+static
+void
+tr_insertionsort(const int *ISAd, int *first, int *last) {
+ int *a, *b;
+ int t, r;
+
+ for(a = first + 1; a < last; ++a) {
+ for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) {
+ do { *(b + 1) = *b; } while((first <= --b) && (*b < 0));
+ if(b < first) { break; }
+ }
+ if(r == 0) { *b = ~*b; }
+ *(b + 1) = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_fixdown(const int *ISAd, int *SA, int i, int size) {
+ int j, k;
+ int v;
+ int c, d, e;
+
+ for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+ d = ISAd[SA[k = j++]];
+ if(d < (e = ISAd[SA[j]])) { k = j; d = e; }
+ if(d <= c) { break; }
+ }
+ SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+tr_heapsort(const int *ISAd, int *SA, int size) {
+ int i, m;
+ int t;
+
+ m = size;
+ if((size % 2) == 0) {
+ m--;
+ if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); }
+ }
+
+ for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); }
+ if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); }
+ for(i = m - 1; 0 < i; --i) {
+ t = SA[0], SA[0] = SA[i];
+ tr_fixdown(ISAd, SA, 0, i);
+ SA[i] = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+int *
+tr_median3(const int *ISAd, int *v1, int *v2, int *v3) {
+ int *t;
+ if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); }
+ if(ISAd[*v2] > ISAd[*v3]) {
+ if(ISAd[*v1] > ISAd[*v3]) { return v1; }
+ else { return v3; }
+ }
+ return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+int *
+tr_median5(const int *ISAd,
+ int *v1, int *v2, int *v3, int *v4, int *v5) {
+ int *t;
+ if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); }
+ if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); }
+ if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); }
+ if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); }
+ if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); }
+ if(ISAd[*v3] > ISAd[*v4]) { return v4; }
+ return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+int *
+tr_pivot(const int *ISAd, int *first, int *last) {
+ int *middle;
+ int t;
+
+ t = last - first;
+ middle = first + t / 2;
+
+ if(t <= 512) {
+ if(t <= 32) {
+ return tr_median3(ISAd, first, middle, last - 1);
+ } else {
+ t >>= 2;
+ return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1);
+ }
+ }
+ t >>= 3;
+ first = tr_median3(ISAd, first, first + t, first + (t << 1));
+ middle = tr_median3(ISAd, middle - t, middle, middle + t);
+ last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1);
+ return tr_median3(ISAd, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _trbudget_t trbudget_t;
+struct _trbudget_t {
+ int chance;
+ int remain;
+ int incval;
+ int count;
+};
+
+static INLINE
+void
+trbudget_init(trbudget_t *budget, int chance, int incval) {
+ budget->chance = chance;
+ budget->remain = budget->incval = incval;
+}
+
+static INLINE
+int
+trbudget_check(trbudget_t *budget, int size) {
+ if(size <= budget->remain) { budget->remain -= size; return 1; }
+ if(budget->chance == 0) { budget->count += size; return 0; }
+ budget->remain += budget->incval - size;
+ budget->chance -= 1;
+ return 1;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_partition(const int *ISAd,
+ int *first, int *middle, int *last,
+ int **pa, int **pb, int v) {
+ int *a, *b, *c, *d, *e, *f;
+ int t, s;
+ int x = 0;
+
+ for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { }
+ if(((a = b) < last) && (x < v)) {
+ for(; (++b < last) && ((x = ISAd[*b]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ }
+ for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { }
+ if((b < (d = c)) && (x > v)) {
+ for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+ for(; b < c;) {
+ SWAP(*b, *c);
+ for(; (++b < c) && ((x = ISAd[*b]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+
+ if(a <= d) {
+ c = b - 1;
+ if((s = a - first) > (t = b - a)) { s = t; }
+ for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ if((s = d - c) > (t = last - d - 1)) { s = t; }
+ for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ first += (b - a), last -= (d - c);
+ }
+ *pa = first, *pb = last;
+}
+
+static
+void
+tr_copy(int *ISA, const int *SA,
+ int *first, int *a, int *b, int *last,
+ int depth) {
+ /* sort suffixes of middle partition
+ by using sorted order of suffixes of left and right partition. */
+ int *c, *d, *e;
+ int s, v;
+
+ v = b - SA - 1;
+ for(c = first, d = a - 1; c <= d; ++c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *++d = s;
+ ISA[s] = d - SA;
+ }
+ }
+ for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *--d = s;
+ ISA[s] = d - SA;
+ }
+ }
+}
+
+static
+void
+tr_partialcopy(int *ISA, const int *SA,
+ int *first, int *a, int *b, int *last,
+ int depth) {
+ int *c, *d, *e;
+ int s, v;
+ int rank, lastrank, newrank = -1;
+
+ v = b - SA - 1;
+ lastrank = -1;
+ for(c = first, d = a - 1; c <= d; ++c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *++d = s;
+ rank = ISA[s + depth];
+ if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+ ISA[s] = newrank;
+ }
+ }
+
+ lastrank = -1;
+ for(e = d; first <= e; --e) {
+ rank = ISA[*e];
+ if(lastrank != rank) { lastrank = rank; newrank = e - SA; }
+ if(newrank != rank) { ISA[*e] = newrank; }
+ }
+
+ lastrank = -1;
+ for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *--d = s;
+ rank = ISA[s + depth];
+ if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+ ISA[s] = newrank;
+ }
+ }
+}
+
+static
+void
+tr_introsort(int *ISA, const int *ISAd,
+ int *SA, int *first, int *last,
+ trbudget_t *budget) {
+#define STACK_SIZE TR_STACKSIZE
+ struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE];
+ int *a, *b, *c;
+ int t;
+ int v, x = 0;
+ int incr = ISAd - ISA;
+ int limit, next;
+ int ssize, trlink = -1;
+
+ for(ssize = 0, limit = tr_ilg(last - first);;) {
+
+ if(limit < 0) {
+ if(limit == -1) {
+ /* tandem repeat partition */
+ tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1);
+
+ /* update ranks */
+ if(a < last) {
+ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+ }
+ if(b < last) {
+ for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; }
+ }
+
+ /* push */
+ if(1 < (b - a)) {
+ STACK_PUSH5(NULL, a, b, 0, 0);
+ STACK_PUSH5(ISAd - incr, first, last, -2, trlink);
+ trlink = ssize - 2;
+ }
+ if((a - first) <= (last - b)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink);
+ last = a, limit = tr_ilg(a - first);
+ } else if(1 < (last - b)) {
+ first = b, limit = tr_ilg(last - b);
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ } else {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink);
+ first = b, limit = tr_ilg(last - b);
+ } else if(1 < (a - first)) {
+ last = a, limit = tr_ilg(a - first);
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ } else if(limit == -2) {
+ /* tandem repeat copy */
+ a = stack[--ssize].b, b = stack[ssize].c;
+ if(stack[ssize].d == 0) {
+ tr_copy(ISA, SA, first, a, b, last, ISAd - ISA);
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA);
+ }
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ } else {
+ /* sorted partition */
+ if(0 <= *first) {
+ a = first;
+ do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a));
+ first = a;
+ }
+ if(first < last) {
+ a = first; do { *a = ~*a; } while(*++a < 0);
+ next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1;
+ if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } }
+
+ /* push */
+ if(trbudget_check(budget, a - first)) {
+ if((a - first) <= (last - a)) {
+ STACK_PUSH5(ISAd, a, last, -3, trlink);
+ ISAd += incr, last = a, limit = next;
+ } else {
+ if(1 < (last - a)) {
+ STACK_PUSH5(ISAd + incr, first, a, next, trlink);
+ first = a, limit = -3;
+ } else {
+ ISAd += incr, last = a, limit = next;
+ }
+ }
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ if(1 < (last - a)) {
+ first = a, limit = -3;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ continue;
+ }
+
+ if((last - first) <= TR_INSERTIONSORT_THRESHOLD) {
+ tr_insertionsort(ISAd, first, last);
+ limit = -3;
+ continue;
+ }
+
+ if(limit-- == 0) {
+ tr_heapsort(ISAd, first, last - first);
+ for(a = last - 1; first < a; a = b) {
+ for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; }
+ }
+ limit = -3;
+ continue;
+ }
+
+ /* choose pivot */
+ a = tr_pivot(ISAd, first, last);
+ SWAP(*first, *a);
+ v = ISAd[*first];
+
+ /* partition */
+ tr_partition(ISAd, first, first + 1, last, &a, &b, v);
+ if((last - first) != (b - a)) {
+ next = (ISA[*a] != v) ? tr_ilg(b - a) : -1;
+
+ /* update ranks */
+ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+ if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } }
+
+ /* push */
+ if((1 < (b - a)) && (trbudget_check(budget, b - a))) {
+ if((a - first) <= (last - b)) {
+ if((last - b) <= (b - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ last = a;
+ } else if(1 < (last - b)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ first = b;
+ } else {
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else if((a - first) <= (b - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ last = a;
+ } else {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ if((a - first) <= (b - a)) {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ first = b;
+ } else if(1 < (a - first)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ last = a;
+ } else {
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else if((last - b) <= (b - a)) {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ first = b;
+ } else {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ }
+ } else {
+ if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; }
+ if((a - first) <= (last - b)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ last = a;
+ } else if(1 < (last - b)) {
+ first = b;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ } else {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ first = b;
+ } else if(1 < (a - first)) {
+ last = a;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ }
+ } else {
+ if(trbudget_check(budget, last - first)) {
+ limit = tr_ilg(last - first), ISAd += incr;
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ }
+#undef STACK_SIZE
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Tandem repeat sort */
+static
+void
+trsort(int *ISA, int *SA, int n, int depth) {
+ int *ISAd;
+ int *first, *last;
+ trbudget_t budget;
+ int t, skip, unsorted;
+
+ trbudget_init(&budget, tr_ilg(n) * 2 / 3, n);
+/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */
+ for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) {
+ first = SA;
+ skip = 0;
+ unsorted = 0;
+ do {
+ if((t = *first) < 0) { first -= t; skip += t; }
+ else {
+ if(skip != 0) { *(first + skip) = skip; skip = 0; }
+ last = SA + ISA[t] + 1;
+ if(1 < (last - first)) {
+ budget.count = 0;
+ tr_introsort(ISA, ISAd, SA, first, last, &budget);
+ if(budget.count != 0) { unsorted += budget.count; }
+ else { skip = first - last; }
+ } else if((last - first) == 1) {
+ skip = -1;
+ }
+ first = last;
+ }
+ } while(first < (SA + n));
+ if(skip != 0) { *(first + skip) = skip; }
+ if(unsorted == 0) { break; }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Sorts suffixes of type B*. */
+static
+int
+sort_typeBstar(const unsigned char *T, int *SA,
+ int *bucket_A, int *bucket_B,
+ int n, int openMP) {
+ int *PAb, *ISAb, *buf;
+#ifdef LIBBSC_OPENMP
+ int *curbuf;
+ int l;
+#endif
+ int i, j, k, t, m, bufsize;
+ int c0, c1;
+#ifdef LIBBSC_OPENMP
+ int d0, d1;
+#endif
+ (void)openMP;
+
+ /* Initialize bucket arrays. */
+ for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; }
+ for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; }
+
+ /* Count the number of occurrences of the first one or two characters of each
+ type A, B and B* suffix. Moreover, store the beginning position of all
+ type B* suffixes into the array SA. */
+ for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) {
+ /* type A suffix. */
+ do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1));
+ if(0 <= i) {
+ /* type B* suffix. */
+ ++BUCKET_BSTAR(c0, c1);
+ SA[--m] = i;
+ /* type B suffix. */
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) {
+ ++BUCKET_B(c0, c1);
+ }
+ }
+ }
+ m = n - m;
+/*
+note:
+ A type B* suffix is lexicographically smaller than a type B suffix that
+ begins with the same first two characters.
+*/
+
+ /* Calculate the index of start/end point of each bucket. */
+ for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) {
+ t = i + BUCKET_A(c0);
+ BUCKET_A(c0) = i + j; /* start point */
+ i = t + BUCKET_B(c0, c0);
+ for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) {
+ j += BUCKET_BSTAR(c0, c1);
+ BUCKET_BSTAR(c0, c1) = j; /* end point */
+ i += BUCKET_B(c0, c1);
+ }
+ }
+
+ if(0 < m) {
+ /* Sort the type B* suffixes by their first two characters. */
+ PAb = SA + n - m; ISAb = SA + m;
+ for(i = m - 2; 0 <= i; --i) {
+ t = PAb[i], c0 = T[t], c1 = T[t + 1];
+ SA[--BUCKET_BSTAR(c0, c1)] = i;
+ }
+ t = PAb[m - 1], c0 = T[t], c1 = T[t + 1];
+ SA[--BUCKET_BSTAR(c0, c1)] = m - 1;
+
+ /* Sort the type B* substrings using sssort. */
+#ifdef LIBBSC_OPENMP
+ if (openMP)
+ {
+ buf = SA + m;
+ c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m;
+#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1)
+ {
+ bufsize = (n - (2 * m)) / omp_get_num_threads();
+ curbuf = buf + omp_get_thread_num() * bufsize;
+ k = 0;
+ for(;;) {
+ #pragma omp critical(sssort_lock)
+ {
+ if(0 < (l = j)) {
+ d0 = c0, d1 = c1;
+ do {
+ k = BUCKET_BSTAR(d0, d1);
+ if(--d1 <= d0) {
+ d1 = ALPHABET_SIZE - 1;
+ if(--d0 < 0) { break; }
+ }
+ } while(((l - k) <= 1) && (0 < (l = k)));
+ c0 = d0, c1 = d1, j = k;
+ }
+ }
+ if(l == 0) { break; }
+ sssort(T, PAb, SA + k, SA + l,
+ curbuf, bufsize, 2, n, *(SA + k) == (m - 1));
+ }
+ }
+ }
+ else
+ {
+ buf = SA + m, bufsize = n - (2 * m);
+ for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {
+ for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {
+ i = BUCKET_BSTAR(c0, c1);
+ if(1 < (j - i)) {
+ sssort(T, PAb, SA + i, SA + j,
+ buf, bufsize, 2, n, *(SA + i) == (m - 1));
+ }
+ }
+ }
+ }
+#else
+ buf = SA + m, bufsize = n - (2 * m);
+ for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {
+ for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {
+ i = BUCKET_BSTAR(c0, c1);
+ if(1 < (j - i)) {
+ sssort(T, PAb, SA + i, SA + j,
+ buf, bufsize, 2, n, *(SA + i) == (m - 1));
+ }
+ }
+ }
+#endif
+
+ /* Compute ranks of type B* substrings. */
+ for(i = m - 1; 0 <= i; --i) {
+ if(0 <= SA[i]) {
+ j = i;
+ do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i]));
+ SA[i + 1] = i - j;
+ if(i <= 0) { break; }
+ }
+ j = i;
+ do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0);
+ ISAb[SA[i]] = j;
+ }
+
+ /* Construct the inverse suffix array of type B* suffixes using trsort. */
+ trsort(ISAb, SA, m, 1);
+
+ /* Set the sorted order of tyoe B* suffixes. */
+ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) {
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { }
+ if(0 <= i) {
+ t = i;
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { }
+ SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t;
+ }
+ }
+
+ /* Calculate the index of start/end point of each bucket. */
+ BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */
+ for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) {
+ i = BUCKET_A(c0 + 1) - 1;
+ for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) {
+ t = i - BUCKET_B(c0, c1);
+ BUCKET_B(c0, c1) = i; /* end point */
+
+ /* Move all type B* suffixes to the correct position. */
+ for(i = t, j = BUCKET_BSTAR(c0, c1);
+ j <= k;
+ --i, --k) { SA[i] = SA[k]; }
+ }
+ BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */
+ BUCKET_B(c0, c0) = i; /* end point */
+ }
+ }
+
+ return m;
+}
+
+/* Constructs the suffix array by using the sorted order of type B* suffixes. */
+static
+void
+construct_SA(const unsigned char *T, int *SA,
+ int *bucket_A, int *bucket_B,
+ int n, int m) {
+ int *i, *j, *k;
+ int s;
+ int c0, c1, c2;
+
+ if(0 < m) {
+ /* Construct the sorted order of type B suffixes by using
+ the sorted order of type B* suffixes. */
+ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+ /* Scan the suffix array from right to left. */
+ for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+ j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+ i <= j;
+ --j) {
+ if(0 < (s = *j)) {
+ assert(T[s] == c1);
+ assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+ assert(T[s - 1] <= T[s]);
+ *j = ~s;
+ c0 = T[--s];
+ if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+ if(c0 != c2) {
+ if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+ k = SA + BUCKET_B(c2 = c0, c1);
+ }
+ assert(k < j); assert(k != NULL);
+ *k-- = s;
+ } else {
+ assert(((s == 0) && (T[s] == c1)) || (s < 0));
+ *j = ~s;
+ }
+ }
+ }
+ }
+
+ /* Construct the suffix array by using
+ the sorted order of type B suffixes. */
+ k = SA + BUCKET_A(c2 = T[n - 1]);
+ *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1);
+ /* Scan the suffix array from left to right. */
+ for(i = SA, j = SA + n; i < j; ++i) {
+ if(0 < (s = *i)) {
+ assert(T[s - 1] >= T[s]);
+ c0 = T[--s];
+ if((s == 0) || (T[s - 1] < c0)) { s = ~s; }
+ if(c0 != c2) {
+ BUCKET_A(c2) = k - SA;
+ k = SA + BUCKET_A(c2 = c0);
+ }
+ assert(i < k);
+ *k++ = s;
+ } else {
+ assert(s < 0);
+ *i = ~s;
+ }
+ }
+}
+
+/* Constructs the burrows-wheeler transformed string directly
+ by using the sorted order of type B* suffixes. */
+static
+int
+construct_BWT(const unsigned char *T, int *SA,
+ int *bucket_A, int *bucket_B,
+ int n, int m) {
+ int *i, *j, *k, *orig;
+ int s;
+ int c0, c1, c2;
+
+ if(0 < m) {
+ /* Construct the sorted order of type B suffixes by using
+ the sorted order of type B* suffixes. */
+ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+ /* Scan the suffix array from right to left. */
+ for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+ j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+ i <= j;
+ --j) {
+ if(0 < (s = *j)) {
+ assert(T[s] == c1);
+ assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+ assert(T[s - 1] <= T[s]);
+ c0 = T[--s];
+ *j = ~((int)c0);
+ if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+ if(c0 != c2) {
+ if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+ k = SA + BUCKET_B(c2 = c0, c1);
+ }
+ assert(k < j); assert(k != NULL);
+ *k-- = s;
+ } else if(s != 0) {
+ *j = ~s;
+#ifndef NDEBUG
+ } else {
+ assert(T[s] == c1);
+#endif
+ }
+ }
+ }
+ }
+
+ /* Construct the BWTed string by using
+ the sorted order of type B suffixes. */
+ k = SA + BUCKET_A(c2 = T[n - 1]);
+ *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1);
+ /* Scan the suffix array from left to right. */
+ for(i = SA, j = SA + n, orig = SA; i < j; ++i) {
+ if(0 < (s = *i)) {
+ assert(T[s - 1] >= T[s]);
+ c0 = T[--s];
+ *i = c0;
+ if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); }
+ if(c0 != c2) {
+ BUCKET_A(c2) = k - SA;
+ k = SA + BUCKET_A(c2 = c0);
+ }
+ assert(i < k);
+ *k++ = s;
+ } else if(s != 0) {
+ *i = ~s;
+ } else {
+ orig = i;
+ }
+ }
+
+ return orig - SA;
+}
+
+/* Constructs the burrows-wheeler transformed string directly
+ by using the sorted order of type B* suffixes. */
+static
+int
+construct_BWT_indexes(const unsigned char *T, int *SA,
+ int *bucket_A, int *bucket_B,
+ int n, int m,
+ unsigned char * num_indexes, int * indexes) {
+ int *i, *j, *k, *orig;
+ int s;
+ int c0, c1, c2;
+
+ int mod = n / 8;
+ {
+ mod |= mod >> 1; mod |= mod >> 2;
+ mod |= mod >> 4; mod |= mod >> 8;
+ mod |= mod >> 16; mod >>= 1;
+
+ *num_indexes = (unsigned char)((n - 1) / (mod + 1));
+ }
+
+ if(0 < m) {
+ /* Construct the sorted order of type B suffixes by using
+ the sorted order of type B* suffixes. */
+ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+ /* Scan the suffix array from right to left. */
+ for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+ j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+ i <= j;
+ --j) {
+ if(0 < (s = *j)) {
+ assert(T[s] == c1);
+ assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+ assert(T[s - 1] <= T[s]);
+
+ if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA;
+
+ c0 = T[--s];
+ *j = ~((int)c0);
+ if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+ if(c0 != c2) {
+ if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+ k = SA + BUCKET_B(c2 = c0, c1);
+ }
+ assert(k < j); assert(k != NULL);
+ *k-- = s;
+ } else if(s != 0) {
+ *j = ~s;
+#ifndef NDEBUG
+ } else {
+ assert(T[s] == c1);
+#endif
+ }
+ }
+ }
+ }
+
+ /* Construct the BWTed string by using
+ the sorted order of type B suffixes. */
+ k = SA + BUCKET_A(c2 = T[n - 1]);
+ if (T[n - 2] < c2) {
+ if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA;
+ *k++ = ~((int)T[n - 2]);
+ }
+ else {
+ *k++ = n - 1;
+ }
+
+ /* Scan the suffix array from left to right. */
+ for(i = SA, j = SA + n, orig = SA; i < j; ++i) {
+ if(0 < (s = *i)) {
+ assert(T[s - 1] >= T[s]);
+
+ if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA;
+
+ c0 = T[--s];
+ *i = c0;
+ if(c0 != c2) {
+ BUCKET_A(c2) = k - SA;
+ k = SA + BUCKET_A(c2 = c0);
+ }
+ assert(i < k);
+ if((0 < s) && (T[s - 1] < c0)) {
+ if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA;
+ *k++ = ~((int)T[s - 1]);
+ } else
+ *k++ = s;
+ } else if(s != 0) {
+ *i = ~s;
+ } else {
+ orig = i;
+ }
+ }
+
+ return orig - SA;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/*- Function -*/
+
+int
+divsufsort(const unsigned char *T, int *SA, int n, int openMP) {
+ int *bucket_A, *bucket_B;
+ int m;
+ int err = 0;
+
+ /* Check arguments. */
+ if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; }
+ else if(n == 0) { return 0; }
+ else if(n == 1) { SA[0] = 0; return 0; }
+ else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; }
+
+ bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));
+ bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));
+
+ /* Suffixsort. */
+ if((bucket_A != NULL) && (bucket_B != NULL)) {
+ m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP);
+ construct_SA(T, SA, bucket_A, bucket_B, n, m);
+ } else {
+ err = -2;
+ }
+
+ free(bucket_B);
+ free(bucket_A);
+
+ return err;
+}
+
+int
+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) {
+ int *B;
+ int *bucket_A, *bucket_B;
+ int m, pidx, i;
+
+ /* Check arguments. */
+ if((T == NULL) || (U == NULL) || (n < 0)) { return -1; }
+ else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; }
+
+ if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); }
+ bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));
+ bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));
+
+ /* Burrows-Wheeler Transform. */
+ if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) {
+ m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP);
+
+ if (num_indexes == NULL || indexes == NULL) {
+ pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m);
+ } else {
+ pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes);
+ }
+
+ /* Copy to output string. */
+ U[0] = T[n - 1];
+ for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; }
+ for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; }
+ pidx += 1;
+ } else {
+ pidx = -2;
+ }
+
+ free(bucket_B);
+ free(bucket_A);
+ if(A == NULL) { free(B); }
+
+ return pidx;
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/divsufsort.h b/Utilities/cmzstd/lib/dictBuilder/divsufsort.h
new file mode 100644
index 000000000..5440994af
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/divsufsort.h
@@ -0,0 +1,67 @@
+/*
+ * divsufsort.h for libdivsufsort-lite
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DIVSUFSORT_H
+#define _DIVSUFSORT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*- Prototypes -*/
+
+/**
+ * Constructs the suffix array of a given string.
+ * @param T [0..n-1] The input string.
+ * @param SA [0..n-1] The output array of suffixes.
+ * @param n The length of the given string.
+ * @param openMP enables OpenMP optimization.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+int
+divsufsort(const unsigned char *T, int *SA, int n, int openMP);
+
+/**
+ * Constructs the burrows-wheeler transformed string of a given string.
+ * @param T [0..n-1] The input string.
+ * @param U [0..n-1] The output string. (can be T)
+ * @param A [0..n-1] The temporary array. (can be NULL)
+ * @param n The length of the given string.
+ * @param num_indexes The length of secondary indexes array. (can be NULL)
+ * @param indexes The secondary indexes array. (can be NULL)
+ * @param openMP enables OpenMP optimization.
+ * @return The primary index if no error occurred, -1 or -2 otherwise.
+ */
+int
+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _DIVSUFSORT_H */
diff --git a/Utilities/cmzstd/lib/dictBuilder/fastcover.c b/Utilities/cmzstd/lib/dictBuilder/fastcover.c
new file mode 100644
index 000000000..c289c0690
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/fastcover.c
@@ -0,0 +1,728 @@
+/*-*************************************
+* Dependencies
+***************************************/
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h> /* clock */
+
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "cover.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+
+/*-*************************************
+* Constants
+***************************************/
+#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
+#define FASTCOVER_MAX_F 31
+#define FASTCOVER_MAX_ACCEL 10
+#define DEFAULT_SPLITPOINT 0.75
+#define DEFAULT_F 20
+#define DEFAULT_ACCEL 1
+
+
+/*-*************************************
+* Console display
+***************************************/
+static int g_displayLevel = 2;
+#define DISPLAY(...) \
+ { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ }
+#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \
+ if (displayLevel >= l) { \
+ DISPLAY(__VA_ARGS__); \
+ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
+#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
+
+#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
+ if (displayLevel >= l) { \
+ if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \
+ g_time = clock(); \
+ DISPLAY(__VA_ARGS__); \
+ } \
+ }
+#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
+static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+
+
+/*-*************************************
+* Hash Functions
+***************************************/
+static const U64 prime6bytes = 227718039650203ULL;
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+
+static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+
+
+/**
+ * Hash the d-byte value pointed to by p and mod 2^f
+ */
+static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) {
+ if (d == 6) {
+ return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1);
+ }
+ return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1);
+}
+
+
+/*-*************************************
+* Acceleration
+***************************************/
+typedef struct {
+ unsigned finalize; /* Percentage of training samples used for ZDICT_finalizeDictionary */
+ unsigned skip; /* Number of dmer skipped between each dmer counted in computeFrequency */
+} FASTCOVER_accel_t;
+
+
+static const FASTCOVER_accel_t FASTCOVER_defaultAccelParameters[FASTCOVER_MAX_ACCEL+1] = {
+ { 100, 0 }, /* accel = 0, should not happen because accel = 0 defaults to accel = 1 */
+ { 100, 0 }, /* accel = 1 */
+ { 50, 1 }, /* accel = 2 */
+ { 34, 2 }, /* accel = 3 */
+ { 25, 3 }, /* accel = 4 */
+ { 20, 4 }, /* accel = 5 */
+ { 17, 5 }, /* accel = 6 */
+ { 14, 6 }, /* accel = 7 */
+ { 13, 7 }, /* accel = 8 */
+ { 11, 8 }, /* accel = 9 */
+ { 10, 9 }, /* accel = 10 */
+};
+
+
+/*-*************************************
+* Context
+***************************************/
+typedef struct {
+ const BYTE *samples;
+ size_t *offsets;
+ const size_t *samplesSizes;
+ size_t nbSamples;
+ size_t nbTrainSamples;
+ size_t nbTestSamples;
+ size_t nbDmers;
+ U32 *freqs;
+ unsigned d;
+ unsigned f;
+ FASTCOVER_accel_t accelParams;
+} FASTCOVER_ctx_t;
+
+
+/*-*************************************
+* Helper functions
+***************************************/
+/**
+ * Selects the best segment in an epoch.
+ * Segments of are scored according to the function:
+ *
+ * Let F(d) be the frequency of all dmers with hash value d.
+ * Let S_i be hash value of the dmer at position i of segment S which has length k.
+ *
+ * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1})
+ *
+ * Once the dmer with hash value d is in the dictionay we set F(d) = 0.
+ */
+static COVER_segment_t FASTCOVER_selectSegment(const FASTCOVER_ctx_t *ctx,
+ U32 *freqs, U32 begin, U32 end,
+ ZDICT_cover_params_t parameters,
+ U16* segmentFreqs) {
+ /* Constants */
+ const U32 k = parameters.k;
+ const U32 d = parameters.d;
+ const U32 f = ctx->f;
+ const U32 dmersInK = k - d + 1;
+
+ /* Try each segment (activeSegment) and save the best (bestSegment) */
+ COVER_segment_t bestSegment = {0, 0, 0};
+ COVER_segment_t activeSegment;
+
+ /* Reset the activeDmers in the segment */
+ /* The activeSegment starts at the beginning of the epoch. */
+ activeSegment.begin = begin;
+ activeSegment.end = begin;
+ activeSegment.score = 0;
+
+ /* Slide the activeSegment through the whole epoch.
+ * Save the best segment in bestSegment.
+ */
+ while (activeSegment.end < end) {
+ /* Get hash value of current dmer */
+ const size_t idx = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.end, f, d);
+
+ /* Add frequency of this index to score if this is the first occurence of index in active segment */
+ if (segmentFreqs[idx] == 0) {
+ activeSegment.score += freqs[idx];
+ }
+ /* Increment end of segment and segmentFreqs*/
+ activeSegment.end += 1;
+ segmentFreqs[idx] += 1;
+ /* If the window is now too large, drop the first position */
+ if (activeSegment.end - activeSegment.begin == dmersInK + 1) {
+ /* Get hash value of the dmer to be eliminated from active segment */
+ const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d);
+ segmentFreqs[delIndex] -= 1;
+ /* Subtract frequency of this index from score if this is the last occurrence of this index in active segment */
+ if (segmentFreqs[delIndex] == 0) {
+ activeSegment.score -= freqs[delIndex];
+ }
+ /* Increment start of segment */
+ activeSegment.begin += 1;
+ }
+
+ /* If this segment is the best so far save it */
+ if (activeSegment.score > bestSegment.score) {
+ bestSegment = activeSegment;
+ }
+ }
+
+ /* Zero out rest of segmentFreqs array */
+ while (activeSegment.begin < end) {
+ const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d);
+ segmentFreqs[delIndex] -= 1;
+ activeSegment.begin += 1;
+ }
+
+ {
+ /* Zero the frequency of hash value of each dmer covered by the chosen segment. */
+ U32 pos;
+ for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+ const size_t i = FASTCOVER_hashPtrToIndex(ctx->samples + pos, f, d);
+ freqs[i] = 0;
+ }
+ }
+
+ return bestSegment;
+}
+
+
+static int FASTCOVER_checkParameters(ZDICT_cover_params_t parameters,
+ size_t maxDictSize, unsigned f,
+ unsigned accel) {
+ /* k, d, and f are required parameters */
+ if (parameters.d == 0 || parameters.k == 0) {
+ return 0;
+ }
+ /* d has to be 6 or 8 */
+ if (parameters.d != 6 && parameters.d != 8) {
+ return 0;
+ }
+ /* k <= maxDictSize */
+ if (parameters.k > maxDictSize) {
+ return 0;
+ }
+ /* d <= k */
+ if (parameters.d > parameters.k) {
+ return 0;
+ }
+ /* 0 < f <= FASTCOVER_MAX_F*/
+ if (f > FASTCOVER_MAX_F || f == 0) {
+ return 0;
+ }
+ /* 0 < splitPoint <= 1 */
+ if (parameters.splitPoint <= 0 || parameters.splitPoint > 1) {
+ return 0;
+ }
+ /* 0 < accel <= 10 */
+ if (accel > 10 || accel == 0) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/**
+ * Clean up a context initialized with `FASTCOVER_ctx_init()`.
+ */
+static void
+FASTCOVER_ctx_destroy(FASTCOVER_ctx_t* ctx)
+{
+ if (!ctx) return;
+
+ free(ctx->freqs);
+ ctx->freqs = NULL;
+
+ free(ctx->offsets);
+ ctx->offsets = NULL;
+}
+
+
+/**
+ * Calculate for frequency of hash value of each dmer in ctx->samples
+ */
+static void
+FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx)
+{
+ const unsigned f = ctx->f;
+ const unsigned d = ctx->d;
+ const unsigned skip = ctx->accelParams.skip;
+ const unsigned readLength = MAX(d, 8);
+ size_t i;
+ assert(ctx->nbTrainSamples >= 5);
+ assert(ctx->nbTrainSamples <= ctx->nbSamples);
+ for (i = 0; i < ctx->nbTrainSamples; i++) {
+ size_t start = ctx->offsets[i]; /* start of current dmer */
+ size_t const currSampleEnd = ctx->offsets[i+1];
+ while (start + readLength <= currSampleEnd) {
+ const size_t dmerIndex = FASTCOVER_hashPtrToIndex(ctx->samples + start, f, d);
+ freqs[dmerIndex]++;
+ start = start + skip + 1;
+ }
+ }
+}
+
+
+/**
+ * Prepare a context for dictionary building.
+ * The context is only dependent on the parameter `d` and can used multiple
+ * times.
+ * Returns 1 on success or zero on error.
+ * The context must be destroyed with `FASTCOVER_ctx_destroy()`.
+ */
+static int
+FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx,
+ const void* samplesBuffer,
+ const size_t* samplesSizes, unsigned nbSamples,
+ unsigned d, double splitPoint, unsigned f,
+ FASTCOVER_accel_t accelParams)
+{
+ const BYTE* const samples = (const BYTE*)samplesBuffer;
+ const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
+ /* Split samples into testing and training sets */
+ const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples;
+ const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples;
+ const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize;
+ const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize;
+
+ /* Checks */
+ if (totalSamplesSize < MAX(d, sizeof(U64)) ||
+ totalSamplesSize >= (size_t)FASTCOVER_MAX_SAMPLES_SIZE) {
+ DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
+ (unsigned)(totalSamplesSize >> 20), (FASTCOVER_MAX_SAMPLES_SIZE >> 20));
+ return 0;
+ }
+
+ /* Check if there are at least 5 training samples */
+ if (nbTrainSamples < 5) {
+ DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid\n", nbTrainSamples);
+ return 0;
+ }
+
+ /* Check if there's testing sample */
+ if (nbTestSamples < 1) {
+ DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.\n", nbTestSamples);
+ return 0;
+ }
+
+ /* Zero the context */
+ memset(ctx, 0, sizeof(*ctx));
+ DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples,
+ (unsigned)trainingSamplesSize);
+ DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples,
+ (unsigned)testSamplesSize);
+
+ ctx->samples = samples;
+ ctx->samplesSizes = samplesSizes;
+ ctx->nbSamples = nbSamples;
+ ctx->nbTrainSamples = nbTrainSamples;
+ ctx->nbTestSamples = nbTestSamples;
+ ctx->nbDmers = trainingSamplesSize - MAX(d, sizeof(U64)) + 1;
+ ctx->d = d;
+ ctx->f = f;
+ ctx->accelParams = accelParams;
+
+ /* The offsets of each file */
+ ctx->offsets = (size_t*)calloc((nbSamples + 1), sizeof(size_t));
+ if (ctx->offsets == NULL) {
+ DISPLAYLEVEL(1, "Failed to allocate scratch buffers \n");
+ FASTCOVER_ctx_destroy(ctx);
+ return 0;
+ }
+
+ /* Fill offsets from the samplesSizes */
+ { U32 i;
+ ctx->offsets[0] = 0;
+ assert(nbSamples >= 5);
+ for (i = 1; i <= nbSamples; ++i) {
+ ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1];
+ }
+ }
+
+ /* Initialize frequency array of size 2^f */
+ ctx->freqs = (U32*)calloc(((U64)1 << f), sizeof(U32));
+ if (ctx->freqs == NULL) {
+ DISPLAYLEVEL(1, "Failed to allocate frequency table \n");
+ FASTCOVER_ctx_destroy(ctx);
+ return 0;
+ }
+
+ DISPLAYLEVEL(2, "Computing frequencies\n");
+ FASTCOVER_computeFrequency(ctx->freqs, ctx);
+
+ return 1;
+}
+
+
+/**
+ * Given the prepared context build the dictionary.
+ */
+static size_t
+FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx,
+ U32* freqs,
+ void* dictBuffer, size_t dictBufferCapacity,
+ ZDICT_cover_params_t parameters,
+ U16* segmentFreqs)
+{
+ BYTE *const dict = (BYTE *)dictBuffer;
+ size_t tail = dictBufferCapacity;
+ /* Divide the data up into epochs of equal size.
+ * We will select at least one segment from each epoch.
+ */
+ const unsigned epochs = MAX(1, (U32)(dictBufferCapacity / parameters.k));
+ const unsigned epochSize = (U32)(ctx->nbDmers / epochs);
+ size_t epoch;
+ DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n",
+ epochs, epochSize);
+ /* Loop through the epochs until there are no more segments or the dictionary
+ * is full.
+ */
+ for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs) {
+ const U32 epochBegin = (U32)(epoch * epochSize);
+ const U32 epochEnd = epochBegin + epochSize;
+ size_t segmentSize;
+ /* Select a segment */
+ COVER_segment_t segment = FASTCOVER_selectSegment(
+ ctx, freqs, epochBegin, epochEnd, parameters, segmentFreqs);
+
+ /* If the segment covers no dmers, then we are out of content */
+ if (segment.score == 0) {
+ break;
+ }
+
+ /* Trim the segment if necessary and if it is too small then we are done */
+ segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
+ if (segmentSize < parameters.d) {
+ break;
+ }
+
+ /* We fill the dictionary from the back to allow the best segments to be
+ * referenced with the smallest offsets.
+ */
+ tail -= segmentSize;
+ memcpy(dict + tail, ctx->samples + segment.begin, segmentSize);
+ DISPLAYUPDATE(
+ 2, "\r%u%% ",
+ (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));
+ }
+ DISPLAYLEVEL(2, "\r%79s\r", "");
+ return tail;
+}
+
+
+/**
+ * Parameters for FASTCOVER_tryParameters().
+ */
+typedef struct FASTCOVER_tryParameters_data_s {
+ const FASTCOVER_ctx_t* ctx;
+ COVER_best_t* best;
+ size_t dictBufferCapacity;
+ ZDICT_cover_params_t parameters;
+} FASTCOVER_tryParameters_data_t;
+
+
+/**
+ * Tries a set of parameters and updates the COVER_best_t with the results.
+ * This function is thread safe if zstd is compiled with multithreaded support.
+ * It takes its parameters as an *OWNING* opaque pointer to support threading.
+ */
+static void FASTCOVER_tryParameters(void *opaque)
+{
+ /* Save parameters as local variables */
+ FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t *)opaque;
+ const FASTCOVER_ctx_t *const ctx = data->ctx;
+ const ZDICT_cover_params_t parameters = data->parameters;
+ size_t dictBufferCapacity = data->dictBufferCapacity;
+ size_t totalCompressedSize = ERROR(GENERIC);
+ /* Initialize array to keep track of frequency of dmer within activeSegment */
+ U16* segmentFreqs = (U16 *)calloc(((U64)1 << ctx->f), sizeof(U16));
+ /* Allocate space for hash table, dict, and freqs */
+ BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+ U32 *freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32));
+ if (!segmentFreqs || !dict || !freqs) {
+ DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");
+ goto _cleanup;
+ }
+ /* Copy the frequencies because we need to modify them */
+ memcpy(freqs, ctx->freqs, ((U64)1 << ctx->f) * sizeof(U32));
+ /* Build the dictionary */
+ { const size_t tail = FASTCOVER_buildDictionary(ctx, freqs, dict, dictBufferCapacity,
+ parameters, segmentFreqs);
+ const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100);
+ dictBufferCapacity = ZDICT_finalizeDictionary(
+ dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+ ctx->samples, ctx->samplesSizes, nbFinalizeSamples, parameters.zParams);
+ if (ZDICT_isError(dictBufferCapacity)) {
+ DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
+ goto _cleanup;
+ }
+ }
+ /* Check total compressed size */
+ totalCompressedSize = COVER_checkTotalCompressedSize(parameters, ctx->samplesSizes,
+ ctx->samples, ctx->offsets,
+ ctx->nbTrainSamples, ctx->nbSamples,
+ dict, dictBufferCapacity);
+_cleanup:
+ COVER_best_finish(data->best, totalCompressedSize, parameters, dict,
+ dictBufferCapacity);
+ free(data);
+ free(segmentFreqs);
+ free(dict);
+ free(freqs);
+}
+
+
+static void
+FASTCOVER_convertToCoverParams(ZDICT_fastCover_params_t fastCoverParams,
+ ZDICT_cover_params_t* coverParams)
+{
+ coverParams->k = fastCoverParams.k;
+ coverParams->d = fastCoverParams.d;
+ coverParams->steps = fastCoverParams.steps;
+ coverParams->nbThreads = fastCoverParams.nbThreads;
+ coverParams->splitPoint = fastCoverParams.splitPoint;
+ coverParams->zParams = fastCoverParams.zParams;
+}
+
+
+static void
+FASTCOVER_convertToFastCoverParams(ZDICT_cover_params_t coverParams,
+ ZDICT_fastCover_params_t* fastCoverParams,
+ unsigned f, unsigned accel)
+{
+ fastCoverParams->k = coverParams.k;
+ fastCoverParams->d = coverParams.d;
+ fastCoverParams->steps = coverParams.steps;
+ fastCoverParams->nbThreads = coverParams.nbThreads;
+ fastCoverParams->splitPoint = coverParams.splitPoint;
+ fastCoverParams->f = f;
+ fastCoverParams->accel = accel;
+ fastCoverParams->zParams = coverParams.zParams;
+}
+
+
+ZDICTLIB_API size_t
+ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer,
+ const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_fastCover_params_t parameters)
+{
+ BYTE* const dict = (BYTE*)dictBuffer;
+ FASTCOVER_ctx_t ctx;
+ ZDICT_cover_params_t coverParams;
+ FASTCOVER_accel_t accelParams;
+ /* Initialize global data */
+ g_displayLevel = parameters.zParams.notificationLevel;
+ /* Assign splitPoint and f if not provided */
+ parameters.splitPoint = 1.0;
+ parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f;
+ parameters.accel = parameters.accel == 0 ? DEFAULT_ACCEL : parameters.accel;
+ /* Convert to cover parameter */
+ memset(&coverParams, 0 , sizeof(coverParams));
+ FASTCOVER_convertToCoverParams(parameters, &coverParams);
+ /* Checks */
+ if (!FASTCOVER_checkParameters(coverParams, dictBufferCapacity, parameters.f,
+ parameters.accel)) {
+ DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n");
+ return ERROR(GENERIC);
+ }
+ if (nbSamples == 0) {
+ DISPLAYLEVEL(1, "FASTCOVER must have at least one input file\n");
+ return ERROR(GENERIC);
+ }
+ if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+ DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+ ZDICT_DICTSIZE_MIN);
+ return ERROR(dstSize_tooSmall);
+ }
+ /* Assign corresponding FASTCOVER_accel_t to accelParams*/
+ accelParams = FASTCOVER_defaultAccelParameters[parameters.accel];
+ /* Initialize context */
+ if (!FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
+ coverParams.d, parameters.splitPoint, parameters.f,
+ accelParams)) {
+ DISPLAYLEVEL(1, "Failed to initialize context\n");
+ return ERROR(GENERIC);
+ }
+ /* Build the dictionary */
+ DISPLAYLEVEL(2, "Building dictionary\n");
+ {
+ /* Initialize array to keep track of frequency of dmer within activeSegment */
+ U16* segmentFreqs = (U16 *)calloc(((U64)1 << parameters.f), sizeof(U16));
+ const size_t tail = FASTCOVER_buildDictionary(&ctx, ctx.freqs, dictBuffer,
+ dictBufferCapacity, coverParams, segmentFreqs);
+ const unsigned nbFinalizeSamples = (unsigned)(ctx.nbTrainSamples * ctx.accelParams.finalize / 100);
+ const size_t dictionarySize = ZDICT_finalizeDictionary(
+ dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+ samplesBuffer, samplesSizes, nbFinalizeSamples, coverParams.zParams);
+ if (!ZSTD_isError(dictionarySize)) {
+ DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
+ (unsigned)dictionarySize);
+ }
+ FASTCOVER_ctx_destroy(&ctx);
+ free(segmentFreqs);
+ return dictionarySize;
+ }
+}
+
+
+ZDICTLIB_API size_t
+ZDICT_optimizeTrainFromBuffer_fastCover(
+ void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer,
+ const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_fastCover_params_t* parameters)
+{
+ ZDICT_cover_params_t coverParams;
+ FASTCOVER_accel_t accelParams;
+ /* constants */
+ const unsigned nbThreads = parameters->nbThreads;
+ const double splitPoint =
+ parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+ const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
+ const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
+ const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
+ const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
+ const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
+ const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
+ const unsigned kIterations =
+ (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
+ const unsigned f = parameters->f == 0 ? DEFAULT_F : parameters->f;
+ const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel;
+ /* Local variables */
+ const int displayLevel = parameters->zParams.notificationLevel;
+ unsigned iteration = 1;
+ unsigned d;
+ unsigned k;
+ COVER_best_t best;
+ POOL_ctx *pool = NULL;
+ /* Checks */
+ if (splitPoint <= 0 || splitPoint > 1) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect splitPoint\n");
+ return ERROR(GENERIC);
+ }
+ if (accel == 0 || accel > FASTCOVER_MAX_ACCEL) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect accel\n");
+ return ERROR(GENERIC);
+ }
+ if (kMinK < kMaxD || kMaxK < kMinK) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect k\n");
+ return ERROR(GENERIC);
+ }
+ if (nbSamples == 0) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "FASTCOVER must have at least one input file\n");
+ return ERROR(GENERIC);
+ }
+ if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "dictBufferCapacity must be at least %u\n",
+ ZDICT_DICTSIZE_MIN);
+ return ERROR(dstSize_tooSmall);
+ }
+ if (nbThreads > 1) {
+ pool = POOL_create(nbThreads, 1);
+ if (!pool) {
+ return ERROR(memory_allocation);
+ }
+ }
+ /* Initialization */
+ COVER_best_init(&best);
+ memset(&coverParams, 0 , sizeof(coverParams));
+ FASTCOVER_convertToCoverParams(*parameters, &coverParams);
+ accelParams = FASTCOVER_defaultAccelParameters[accel];
+ /* Turn down global display level to clean up display at level 2 and below */
+ g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
+ /* Loop through d first because each new value needs a new context */
+ LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
+ kIterations);
+ for (d = kMinD; d <= kMaxD; d += 2) {
+ /* Initialize the context for this value of d */
+ FASTCOVER_ctx_t ctx;
+ LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
+ if (!FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams)) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return ERROR(GENERIC);
+ }
+ /* Loop through k reusing the same context */
+ for (k = kMinK; k <= kMaxK; k += kStepSize) {
+ /* Prepare the arguments */
+ FASTCOVER_tryParameters_data_t *data = (FASTCOVER_tryParameters_data_t *)malloc(
+ sizeof(FASTCOVER_tryParameters_data_t));
+ LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
+ if (!data) {
+ LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
+ COVER_best_destroy(&best);
+ FASTCOVER_ctx_destroy(&ctx);
+ POOL_free(pool);
+ return ERROR(GENERIC);
+ }
+ data->ctx = &ctx;
+ data->best = &best;
+ data->dictBufferCapacity = dictBufferCapacity;
+ data->parameters = coverParams;
+ data->parameters.k = k;
+ data->parameters.d = d;
+ data->parameters.splitPoint = splitPoint;
+ data->parameters.steps = kSteps;
+ data->parameters.zParams.notificationLevel = g_displayLevel;
+ /* Check the parameters */
+ if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity,
+ data->ctx->f, accel)) {
+ DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n");
+ free(data);
+ continue;
+ }
+ /* Call the function and pass ownership of data to it */
+ COVER_best_start(&best);
+ if (pool) {
+ POOL_add(pool, &FASTCOVER_tryParameters, data);
+ } else {
+ FASTCOVER_tryParameters(data);
+ }
+ /* Print status */
+ LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ",
+ (unsigned)((iteration * 100) / kIterations));
+ ++iteration;
+ }
+ COVER_best_wait(&best);
+ FASTCOVER_ctx_destroy(&ctx);
+ }
+ LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
+ /* Fill the output buffer and parameters with output of the best parameters */
+ {
+ const size_t dictSize = best.dictSize;
+ if (ZSTD_isError(best.compressedSize)) {
+ const size_t compressedSize = best.compressedSize;
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return compressedSize;
+ }
+ FASTCOVER_convertToFastCoverParams(best.parameters, parameters, f, accel);
+ memcpy(dictBuffer, best.dict, dictSize);
+ COVER_best_destroy(&best);
+ POOL_free(pool);
+ return dictSize;
+ }
+
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/zdict.c b/Utilities/cmzstd/lib/dictBuilder/zdict.c
new file mode 100644
index 000000000..c753da0db
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/zdict.c
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/*-**************************************
+* Tuning parameters
+****************************************/
+#define MINRATIO 4 /* minimum nb of apparition to be selected in dictionary */
+#define ZDICT_MAX_SAMPLES_SIZE (2000U << 20)
+#define ZDICT_MIN_SAMPLES_SIZE (ZDICT_CONTENTSIZE_MIN * MINRATIO)
+
+
+/*-**************************************
+* Compiler Options
+****************************************/
+/* Unix Large Files support (>4GB) */
+#define _FILE_OFFSET_BITS 64
+#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */
+# define _LARGEFILE_SOURCE
+#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */
+# define _LARGEFILE64_SOURCE
+#endif
+
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memset */
+#include <stdio.h> /* fprintf, fopen, ftello64 */
+#include <time.h> /* clock */
+
+#include "mem.h" /* read */
+#include "fse.h" /* FSE_normalizeCount, FSE_writeNCount */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h" /* HUF_buildCTable, HUF_writeCTable */
+#include "zstd_internal.h" /* includes zstd.h */
+#include "xxhash.h" /* XXH64 */
+#include "divsufsort.h"
+#ifndef ZDICT_STATIC_LINKING_ONLY
+# define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+
+/*-*************************************
+* Constants
+***************************************/
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define DICTLISTSIZE_DEFAULT 10000
+
+#define NOISELENGTH 32
+
+static const int g_compressionLevel_default = 3;
+static const U32 g_selectivity_default = 9;
+
+
+/*-*************************************
+* Console display
+***************************************/
+#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }
+#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
+
+static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
+
+static void ZDICT_printHex(const void* ptr, size_t length)
+{
+ const BYTE* const b = (const BYTE*)ptr;
+ size_t u;
+ for (u=0; u<length; u++) {
+ BYTE c = b[u];
+ if (c<32 || c>126) c = '.'; /* non-printable char */
+ DISPLAY("%c", c);
+ }
+}
+
+
+/*-********************************************************
+* Helper functions
+**********************************************************/
+unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); }
+
+const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
+
+unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize)
+{
+ if (dictSize < 8) return 0;
+ if (MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return 0;
+ return MEM_readLE32((const char*)dictBuffer + 4);
+}
+
+
+/*-********************************************************
+* Dictionary training functions
+**********************************************************/
+static unsigned ZDICT_NbCommonBytes (size_t val)
+{
+ if (MEM_isLittleEndian()) {
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ _BitScanForward64( &r, (U64)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r=0;
+ _BitScanForward( &r, (U32)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ } else { /* Big Endian CPU */
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_clzll(val) >> 3);
+# else
+ unsigned r;
+ const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
+ if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r = 0;
+ _BitScanReverse( &r, (unsigned long)val );
+ return (unsigned)(r>>3);
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } }
+}
+
+
+/*! ZDICT_count() :
+ Count the nb of common bytes between 2 pointers.
+ Note : this function presumes end of buffer followed by noisy guard band.
+*/
+static size_t ZDICT_count(const void* pIn, const void* pMatch)
+{
+ const char* const pStart = (const char*)pIn;
+ for (;;) {
+ size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+ if (!diff) {
+ pIn = (const char*)pIn+sizeof(size_t);
+ pMatch = (const char*)pMatch+sizeof(size_t);
+ continue;
+ }
+ pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff);
+ return (size_t)((const char*)pIn - pStart);
+ }
+}
+
+
+typedef struct {
+ U32 pos;
+ U32 length;
+ U32 savings;
+} dictItem;
+
+static void ZDICT_initDictItem(dictItem* d)
+{
+ d->pos = 1;
+ d->length = 0;
+ d->savings = (U32)(-1);
+}
+
+
+#define LLIMIT 64 /* heuristic determined experimentally */
+#define MINMATCHLENGTH 7 /* heuristic determined experimentally */
+static dictItem ZDICT_analyzePos(
+ BYTE* doneMarks,
+ const int* suffix, U32 start,
+ const void* buffer, U32 minRatio, U32 notificationLevel)
+{
+ U32 lengthList[LLIMIT] = {0};
+ U32 cumulLength[LLIMIT] = {0};
+ U32 savings[LLIMIT] = {0};
+ const BYTE* b = (const BYTE*)buffer;
+ size_t maxLength = LLIMIT;
+ size_t pos = suffix[start];
+ U32 end = start;
+ dictItem solution;
+
+ /* init */
+ memset(&solution, 0, sizeof(solution));
+ doneMarks[pos] = 1;
+
+ /* trivial repetition cases */
+ if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2))
+ ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3))
+ ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {
+ /* skip and mark segment */
+ U16 const pattern16 = MEM_read16(b+pos+4);
+ U32 u, patternEnd = 6;
+ while (MEM_read16(b+pos+patternEnd) == pattern16) patternEnd+=2 ;
+ if (b[pos+patternEnd] == b[pos+patternEnd-1]) patternEnd++;
+ for (u=1; u<patternEnd; u++)
+ doneMarks[pos+u] = 1;
+ return solution;
+ }
+
+ /* look forward */
+ { size_t length;
+ do {
+ end++;
+ length = ZDICT_count(b + pos, b + suffix[end]);
+ } while (length >= MINMATCHLENGTH);
+ }
+
+ /* look backward */
+ { size_t length;
+ do {
+ length = ZDICT_count(b + pos, b + *(suffix+start-1));
+ if (length >=MINMATCHLENGTH) start--;
+ } while(length >= MINMATCHLENGTH);
+ }
+
+ /* exit if not found a minimum nb of repetitions */
+ if (end-start < minRatio) {
+ U32 idx;
+ for(idx=start; idx<end; idx++)
+ doneMarks[suffix[idx]] = 1;
+ return solution;
+ }
+
+ { int i;
+ U32 mml;
+ U32 refinedStart = start;
+ U32 refinedEnd = end;
+
+ DISPLAYLEVEL(4, "\n");
+ DISPLAYLEVEL(4, "found %3u matches of length >= %i at pos %7u ", (unsigned)(end-start), MINMATCHLENGTH, (unsigned)pos);
+ DISPLAYLEVEL(4, "\n");
+
+ for (mml = MINMATCHLENGTH ; ; mml++) {
+ BYTE currentChar = 0;
+ U32 currentCount = 0;
+ U32 currentID = refinedStart;
+ U32 id;
+ U32 selectedCount = 0;
+ U32 selectedID = currentID;
+ for (id =refinedStart; id < refinedEnd; id++) {
+ if (b[suffix[id] + mml] != currentChar) {
+ if (currentCount > selectedCount) {
+ selectedCount = currentCount;
+ selectedID = currentID;
+ }
+ currentID = id;
+ currentChar = b[ suffix[id] + mml];
+ currentCount = 0;
+ }
+ currentCount ++;
+ }
+ if (currentCount > selectedCount) { /* for last */
+ selectedCount = currentCount;
+ selectedID = currentID;
+ }
+
+ if (selectedCount < minRatio)
+ break;
+ refinedStart = selectedID;
+ refinedEnd = refinedStart + selectedCount;
+ }
+
+ /* evaluate gain based on new dict */
+ start = refinedStart;
+ pos = suffix[refinedStart];
+ end = start;
+ memset(lengthList, 0, sizeof(lengthList));
+
+ /* look forward */
+ { size_t length;
+ do {
+ end++;
+ length = ZDICT_count(b + pos, b + suffix[end]);
+ if (length >= LLIMIT) length = LLIMIT-1;
+ lengthList[length]++;
+ } while (length >=MINMATCHLENGTH);
+ }
+
+ /* look backward */
+ { size_t length = MINMATCHLENGTH;
+ while ((length >= MINMATCHLENGTH) & (start > 0)) {
+ length = ZDICT_count(b + pos, b + suffix[start - 1]);
+ if (length >= LLIMIT) length = LLIMIT - 1;
+ lengthList[length]++;
+ if (length >= MINMATCHLENGTH) start--;
+ }
+ }
+
+ /* largest useful length */
+ memset(cumulLength, 0, sizeof(cumulLength));
+ cumulLength[maxLength-1] = lengthList[maxLength-1];
+ for (i=(int)(maxLength-2); i>=0; i--)
+ cumulLength[i] = cumulLength[i+1] + lengthList[i];
+
+ for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break;
+ maxLength = i;
+
+ /* reduce maxLength in case of final into repetitive data */
+ { U32 l = (U32)maxLength;
+ BYTE const c = b[pos + maxLength-1];
+ while (b[pos+l-2]==c) l--;
+ maxLength = l;
+ }
+ if (maxLength < MINMATCHLENGTH) return solution; /* skip : no long-enough solution */
+
+ /* calculate savings */
+ savings[5] = 0;
+ for (i=MINMATCHLENGTH; i<=(int)maxLength; i++)
+ savings[i] = savings[i-1] + (lengthList[i] * (i-3));
+
+ DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n",
+ (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / maxLength);
+
+ solution.pos = (U32)pos;
+ solution.length = (U32)maxLength;
+ solution.savings = savings[maxLength];
+
+ /* mark positions done */
+ { U32 id;
+ for (id=start; id<end; id++) {
+ U32 p, pEnd, length;
+ U32 const testedPos = suffix[id];
+ if (testedPos == pos)
+ length = solution.length;
+ else {
+ length = (U32)ZDICT_count(b+pos, b+testedPos);
+ if (length > solution.length) length = solution.length;
+ }
+ pEnd = (U32)(testedPos + length);
+ for (p=testedPos; p<pEnd; p++)
+ doneMarks[p] = 1;
+ } } }
+
+ return solution;
+}
+
+
+static int isIncluded(const void* in, const void* container, size_t length)
+{
+ const char* const ip = (const char*) in;
+ const char* const into = (const char*) container;
+ size_t u;
+
+ for (u=0; u<length; u++) { /* works because end of buffer is a noisy guard band */
+ if (ip[u] != into[u]) break;
+ }
+
+ return u==length;
+}
+
+/*! ZDICT_tryMerge() :
+ check if dictItem can be merged, do it if possible
+ @return : id of destination elt, 0 if not merged
+*/
+static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const void* buffer)
+{
+ const U32 tableSize = table->pos;
+ const U32 eltEnd = elt.pos + elt.length;
+ const char* const buf = (const char*) buffer;
+
+ /* tail overlap */
+ U32 u; for (u=1; u<tableSize; u++) {
+ if (u==eltNbToSkip) continue;
+ if ((table[u].pos > elt.pos) && (table[u].pos <= eltEnd)) { /* overlap, existing > new */
+ /* append */
+ U32 const addedLength = table[u].pos - elt.pos;
+ table[u].length += addedLength;
+ table[u].pos = elt.pos;
+ table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */
+ table[u].savings += elt.length / 8; /* rough approx bonus */
+ elt = table[u];
+ /* sort : improve rank */
+ while ((u>1) && (table[u-1].savings < elt.savings))
+ table[u] = table[u-1], u--;
+ table[u] = elt;
+ return u;
+ } }
+
+ /* front overlap */
+ for (u=1; u<tableSize; u++) {
+ if (u==eltNbToSkip) continue;
+
+ if ((table[u].pos + table[u].length >= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */
+ /* append */
+ int const addedLength = (int)eltEnd - (table[u].pos + table[u].length);
+ table[u].savings += elt.length / 8; /* rough approx bonus */
+ if (addedLength > 0) { /* otherwise, elt fully included into existing */
+ table[u].length += addedLength;
+ table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */
+ }
+ /* sort : improve rank */
+ elt = table[u];
+ while ((u>1) && (table[u-1].savings < elt.savings))
+ table[u] = table[u-1], u--;
+ table[u] = elt;
+ return u;
+ }
+
+ if (MEM_read64(buf + table[u].pos) == MEM_read64(buf + elt.pos + 1)) {
+ if (isIncluded(buf + table[u].pos, buf + elt.pos + 1, table[u].length)) {
+ size_t const addedLength = MAX( (int)elt.length - (int)table[u].length , 1 );
+ table[u].pos = elt.pos;
+ table[u].savings += (U32)(elt.savings * addedLength / elt.length);
+ table[u].length = MIN(elt.length, table[u].length + 1);
+ return u;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void ZDICT_removeDictItem(dictItem* table, U32 id)
+{
+ /* convention : table[0].pos stores nb of elts */
+ U32 const max = table[0].pos;
+ U32 u;
+ if (!id) return; /* protection, should never happen */
+ for (u=id; u<max-1; u++)
+ table[u] = table[u+1];
+ table->pos--;
+}
+
+
+static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt, const void* buffer)
+{
+ /* merge if possible */
+ U32 mergeId = ZDICT_tryMerge(table, elt, 0, buffer);
+ if (mergeId) {
+ U32 newMerge = 1;
+ while (newMerge) {
+ newMerge = ZDICT_tryMerge(table, table[mergeId], mergeId, buffer);
+ if (newMerge) ZDICT_removeDictItem(table, mergeId);
+ mergeId = newMerge;
+ }
+ return;
+ }
+
+ /* insert */
+ { U32 current;
+ U32 nextElt = table->pos;
+ if (nextElt >= maxSize) nextElt = maxSize-1;
+ current = nextElt-1;
+ while (table[current].savings < elt.savings) {
+ table[current+1] = table[current];
+ current--;
+ }
+ table[current+1] = elt;
+ table->pos = nextElt+1;
+ }
+}
+
+
+static U32 ZDICT_dictSize(const dictItem* dictList)
+{
+ U32 u, dictSize = 0;
+ for (u=1; u<dictList[0].pos; u++)
+ dictSize += dictList[u].length;
+ return dictSize;
+}
+
+
+static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize,
+ const void* const buffer, size_t bufferSize, /* buffer must end with noisy guard band */
+ const size_t* fileSizes, unsigned nbFiles,
+ unsigned minRatio, U32 notificationLevel)
+{
+ int* const suffix0 = (int*)malloc((bufferSize+2)*sizeof(*suffix0));
+ int* const suffix = suffix0+1;
+ U32* reverseSuffix = (U32*)malloc((bufferSize)*sizeof(*reverseSuffix));
+ BYTE* doneMarks = (BYTE*)malloc((bufferSize+16)*sizeof(*doneMarks)); /* +16 for overflow security */
+ U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos));
+ size_t result = 0;
+ clock_t displayClock = 0;
+ clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
+
+# define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \
+ if (ZDICT_clockSpan(displayClock) > refreshRate) \
+ { displayClock = clock(); DISPLAY(__VA_ARGS__); \
+ if (notificationLevel>=4) fflush(stderr); } }
+
+ /* init */
+ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */
+ if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) {
+ result = ERROR(memory_allocation);
+ goto _cleanup;
+ }
+ if (minRatio < MINRATIO) minRatio = MINRATIO;
+ memset(doneMarks, 0, bufferSize+16);
+
+ /* limit sample set size (divsufsort limitation)*/
+ if (bufferSize > ZDICT_MAX_SAMPLES_SIZE) DISPLAYLEVEL(3, "sample set too large : reduced to %u MB ...\n", (unsigned)(ZDICT_MAX_SAMPLES_SIZE>>20));
+ while (bufferSize > ZDICT_MAX_SAMPLES_SIZE) bufferSize -= fileSizes[--nbFiles];
+
+ /* sort */
+ DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (unsigned)(bufferSize>>20));
+ { int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0);
+ if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; }
+ }
+ suffix[bufferSize] = (int)bufferSize; /* leads into noise */
+ suffix0[0] = (int)bufferSize; /* leads into noise */
+ /* build reverse suffix sort */
+ { size_t pos;
+ for (pos=0; pos < bufferSize; pos++)
+ reverseSuffix[suffix[pos]] = (U32)pos;
+ /* note filePos tracks borders between samples.
+ It's not used at this stage, but planned to become useful in a later update */
+ filePos[0] = 0;
+ for (pos=1; pos<nbFiles; pos++)
+ filePos[pos] = (U32)(filePos[pos-1] + fileSizes[pos-1]);
+ }
+
+ DISPLAYLEVEL(2, "finding patterns ... \n");
+ DISPLAYLEVEL(3, "minimum ratio : %u \n", minRatio);
+
+ { U32 cursor; for (cursor=0; cursor < bufferSize; ) {
+ dictItem solution;
+ if (doneMarks[cursor]) { cursor++; continue; }
+ solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio, notificationLevel);
+ if (solution.length==0) { cursor++; continue; }
+ ZDICT_insertDictItem(dictList, dictListSize, solution, buffer);
+ cursor += solution.length;
+ DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100);
+ } }
+
+_cleanup:
+ free(suffix0);
+ free(reverseSuffix);
+ free(doneMarks);
+ free(filePos);
+ return result;
+}
+
+
+static void ZDICT_fillNoise(void* buffer, size_t length)
+{
+ unsigned const prime1 = 2654435761U;
+ unsigned const prime2 = 2246822519U;
+ unsigned acc = prime1;
+ size_t p=0;;
+ for (p=0; p<length; p++) {
+ acc *= prime2;
+ ((unsigned char*)buffer)[p] = (unsigned char)(acc >> 21);
+ }
+}
+
+
+typedef struct
+{
+ ZSTD_CDict* dict; /* dictionary */
+ ZSTD_CCtx* zc; /* working context */
+ void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */
+} EStats_ress_t;
+
+#define MAXREPOFFSET 1024
+
+static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
+ unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets,
+ const void* src, size_t srcSize,
+ U32 notificationLevel)
+{
+ size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog);
+ size_t cSize;
+
+ if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */
+ { size_t const errorCode = ZSTD_compressBegin_usingCDict(esr.zc, esr.dict);
+ if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_compressBegin_usingCDict failed \n"); return; }
+
+ }
+ cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize);
+ if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (unsigned)srcSize); return; }
+
+ if (cSize) { /* if == 0; block is not compressible */
+ const seqStore_t* const seqStorePtr = ZSTD_getSeqStore(esr.zc);
+
+ /* literals stats */
+ { const BYTE* bytePtr;
+ for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++)
+ countLit[*bytePtr]++;
+ }
+
+ /* seqStats */
+ { U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ ZSTD_seqToCodes(seqStorePtr);
+
+ { const BYTE* codePtr = seqStorePtr->ofCode;
+ U32 u;
+ for (u=0; u<nbSeq; u++) offsetcodeCount[codePtr[u]]++;
+ }
+
+ { const BYTE* codePtr = seqStorePtr->mlCode;
+ U32 u;
+ for (u=0; u<nbSeq; u++) matchlengthCount[codePtr[u]]++;
+ }
+
+ { const BYTE* codePtr = seqStorePtr->llCode;
+ U32 u;
+ for (u=0; u<nbSeq; u++) litlengthCount[codePtr[u]]++;
+ }
+
+ if (nbSeq >= 2) { /* rep offsets */
+ const seqDef* const seq = seqStorePtr->sequencesStart;
+ U32 offset1 = seq[0].offset - 3;
+ U32 offset2 = seq[1].offset - 3;
+ if (offset1 >= MAXREPOFFSET) offset1 = 0;
+ if (offset2 >= MAXREPOFFSET) offset2 = 0;
+ repOffsets[offset1] += 3;
+ repOffsets[offset2] += 1;
+ } } }
+}
+
+static size_t ZDICT_totalSampleSize(const size_t* fileSizes, unsigned nbFiles)
+{
+ size_t total=0;
+ unsigned u;
+ for (u=0; u<nbFiles; u++) total += fileSizes[u];
+ return total;
+}
+
+typedef struct { U32 offset; U32 count; } offsetCount_t;
+
+static void ZDICT_insertSortCount(offsetCount_t table[ZSTD_REP_NUM+1], U32 val, U32 count)
+{
+ U32 u;
+ table[ZSTD_REP_NUM].offset = val;
+ table[ZSTD_REP_NUM].count = count;
+ for (u=ZSTD_REP_NUM; u>0; u--) {
+ offsetCount_t tmp;
+ if (table[u-1].count >= table[u].count) break;
+ tmp = table[u-1];
+ table[u-1] = table[u];
+ table[u] = tmp;
+ }
+}
+
+/* ZDICT_flatLit() :
+ * rewrite `countLit` to contain a mostly flat but still compressible distribution of literals.
+ * necessary to avoid generating a non-compressible distribution that HUF_writeCTable() cannot encode.
+ */
+static void ZDICT_flatLit(unsigned* countLit)
+{
+ int u;
+ for (u=1; u<256; u++) countLit[u] = 2;
+ countLit[0] = 4;
+ countLit[253] = 1;
+ countLit[254] = 1;
+}
+
+#define OFFCODE_MAX 30 /* only applicable to first block */
+static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
+ unsigned compressionLevel,
+ const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles,
+ const void* dictBuffer, size_t dictBufferSize,
+ unsigned notificationLevel)
+{
+ unsigned countLit[256];
+ HUF_CREATE_STATIC_CTABLE(hufTable, 255);
+ unsigned offcodeCount[OFFCODE_MAX+1];
+ short offcodeNCount[OFFCODE_MAX+1];
+ U32 offcodeMax = ZSTD_highbit32((U32)(dictBufferSize + 128 KB));
+ unsigned matchLengthCount[MaxML+1];
+ short matchLengthNCount[MaxML+1];
+ unsigned litLengthCount[MaxLL+1];
+ short litLengthNCount[MaxLL+1];
+ U32 repOffset[MAXREPOFFSET];
+ offsetCount_t bestRepOffset[ZSTD_REP_NUM+1];
+ EStats_ress_t esr = { NULL, NULL, NULL };
+ ZSTD_parameters params;
+ U32 u, huffLog = 11, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total;
+ size_t pos = 0, errorCode;
+ size_t eSize = 0;
+ size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles);
+ size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles);
+ BYTE* dstPtr = (BYTE*)dstBuffer;
+
+ /* init */
+ DEBUGLOG(4, "ZDICT_analyzeEntropy");
+ if (offcodeMax>OFFCODE_MAX) { eSize = ERROR(dictionaryCreation_failed); goto _cleanup; } /* too large dictionary */
+ for (u=0; u<256; u++) countLit[u] = 1; /* any character must be described */
+ for (u=0; u<=offcodeMax; u++) offcodeCount[u] = 1;
+ for (u=0; u<=MaxML; u++) matchLengthCount[u] = 1;
+ for (u=0; u<=MaxLL; u++) litLengthCount[u] = 1;
+ memset(repOffset, 0, sizeof(repOffset));
+ repOffset[1] = repOffset[4] = repOffset[8] = 1;
+ memset(bestRepOffset, 0, sizeof(bestRepOffset));
+ if (compressionLevel==0) compressionLevel = g_compressionLevel_default;
+ params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);
+
+ esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem);
+ esr.zc = ZSTD_createCCtx();
+ esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
+ if (!esr.dict || !esr.zc || !esr.workPlace) {
+ eSize = ERROR(memory_allocation);
+ DISPLAYLEVEL(1, "Not enough memory \n");
+ goto _cleanup;
+ }
+
+ /* collect stats on all samples */
+ for (u=0; u<nbFiles; u++) {
+ ZDICT_countEStats(esr, params,
+ countLit, offcodeCount, matchLengthCount, litLengthCount, repOffset,
+ (const char*)srcBuffer + pos, fileSizes[u],
+ notificationLevel);
+ pos += fileSizes[u];
+ }
+
+ /* analyze, build stats, starting with literals */
+ { size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+ if (HUF_isError(maxNbBits)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, " HUF_buildCTable error \n");
+ goto _cleanup;
+ }
+ if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */
+ DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n");
+ ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */
+ maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+ assert(maxNbBits==9);
+ }
+ huffLog = (U32)maxNbBits;
+ }
+
+ /* looking for most common first offsets */
+ { U32 offset;
+ for (offset=1; offset<MAXREPOFFSET; offset++)
+ ZDICT_insertSortCount(bestRepOffset, offset, repOffset[offset]);
+ }
+ /* note : the result of this phase should be used to better appreciate the impact on statistics */
+
+ total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u];
+ errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax);
+ if (FSE_isError(errorCode)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n");
+ goto _cleanup;
+ }
+ Offlog = (U32)errorCode;
+
+ total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u];
+ errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML);
+ if (FSE_isError(errorCode)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n");
+ goto _cleanup;
+ }
+ mlLog = (U32)errorCode;
+
+ total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u];
+ errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL);
+ if (FSE_isError(errorCode)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n");
+ goto _cleanup;
+ }
+ llLog = (U32)errorCode;
+
+ /* write result to buffer */
+ { size_t const hhSize = HUF_writeCTable(dstPtr, maxDstSize, hufTable, 255, huffLog);
+ if (HUF_isError(hhSize)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "HUF_writeCTable error \n");
+ goto _cleanup;
+ }
+ dstPtr += hhSize;
+ maxDstSize -= hhSize;
+ eSize += hhSize;
+ }
+
+ { size_t const ohSize = FSE_writeNCount(dstPtr, maxDstSize, offcodeNCount, OFFCODE_MAX, Offlog);
+ if (FSE_isError(ohSize)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_writeNCount error with offcodeNCount \n");
+ goto _cleanup;
+ }
+ dstPtr += ohSize;
+ maxDstSize -= ohSize;
+ eSize += ohSize;
+ }
+
+ { size_t const mhSize = FSE_writeNCount(dstPtr, maxDstSize, matchLengthNCount, MaxML, mlLog);
+ if (FSE_isError(mhSize)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_writeNCount error with matchLengthNCount \n");
+ goto _cleanup;
+ }
+ dstPtr += mhSize;
+ maxDstSize -= mhSize;
+ eSize += mhSize;
+ }
+
+ { size_t const lhSize = FSE_writeNCount(dstPtr, maxDstSize, litLengthNCount, MaxLL, llLog);
+ if (FSE_isError(lhSize)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "FSE_writeNCount error with litlengthNCount \n");
+ goto _cleanup;
+ }
+ dstPtr += lhSize;
+ maxDstSize -= lhSize;
+ eSize += lhSize;
+ }
+
+ if (maxDstSize<12) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, "not enough space to write RepOffsets \n");
+ goto _cleanup;
+ }
+# if 0
+ MEM_writeLE32(dstPtr+0, bestRepOffset[0].offset);
+ MEM_writeLE32(dstPtr+4, bestRepOffset[1].offset);
+ MEM_writeLE32(dstPtr+8, bestRepOffset[2].offset);
+#else
+ /* at this stage, we don't use the result of "most common first offset",
+ as the impact of statistics is not properly evaluated */
+ MEM_writeLE32(dstPtr+0, repStartValue[0]);
+ MEM_writeLE32(dstPtr+4, repStartValue[1]);
+ MEM_writeLE32(dstPtr+8, repStartValue[2]);
+#endif
+ eSize += 12;
+
+_cleanup:
+ ZSTD_freeCDict(esr.dict);
+ ZSTD_freeCCtx(esr.zc);
+ free(esr.workPlace);
+
+ return eSize;
+}
+
+
+
+size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
+ const void* customDictContent, size_t dictContentSize,
+ const void* samplesBuffer, const size_t* samplesSizes,
+ unsigned nbSamples, ZDICT_params_t params)
+{
+ size_t hSize;
+#define HBUFFSIZE 256 /* should prove large enough for all entropy headers */
+ BYTE header[HBUFFSIZE];
+ int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+ U32 const notificationLevel = params.notificationLevel;
+
+ /* check conditions */
+ DEBUGLOG(4, "ZDICT_finalizeDictionary");
+ if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall);
+ if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong);
+ if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall);
+
+ /* dictionary header */
+ MEM_writeLE32(header, ZSTD_MAGIC_DICTIONARY);
+ { U64 const randomID = XXH64(customDictContent, dictContentSize, 0);
+ U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;
+ U32 const dictID = params.dictID ? params.dictID : compliantID;
+ MEM_writeLE32(header+4, dictID);
+ }
+ hSize = 8;
+
+ /* entropy tables */
+ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */
+ DISPLAYLEVEL(2, "statistics ... \n");
+ { size_t const eSize = ZDICT_analyzeEntropy(header+hSize, HBUFFSIZE-hSize,
+ compressionLevel,
+ samplesBuffer, samplesSizes, nbSamples,
+ customDictContent, dictContentSize,
+ notificationLevel);
+ if (ZDICT_isError(eSize)) return eSize;
+ hSize += eSize;
+ }
+
+ /* copy elements in final buffer ; note : src and dst buffer can overlap */
+ if (hSize + dictContentSize > dictBufferCapacity) dictContentSize = dictBufferCapacity - hSize;
+ { size_t const dictSize = hSize + dictContentSize;
+ char* dictEnd = (char*)dictBuffer + dictSize;
+ memmove(dictEnd - dictContentSize, customDictContent, dictContentSize);
+ memcpy(dictBuffer, header, hSize);
+ return dictSize;
+ }
+}
+
+
+static size_t ZDICT_addEntropyTablesFromBuffer_advanced(
+ void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_params_t params)
+{
+ int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+ U32 const notificationLevel = params.notificationLevel;
+ size_t hSize = 8;
+
+ /* calculate entropy tables */
+ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */
+ DISPLAYLEVEL(2, "statistics ... \n");
+ { size_t const eSize = ZDICT_analyzeEntropy((char*)dictBuffer+hSize, dictBufferCapacity-hSize,
+ compressionLevel,
+ samplesBuffer, samplesSizes, nbSamples,
+ (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize,
+ notificationLevel);
+ if (ZDICT_isError(eSize)) return eSize;
+ hSize += eSize;
+ }
+
+ /* add dictionary header (after entropy tables) */
+ MEM_writeLE32(dictBuffer, ZSTD_MAGIC_DICTIONARY);
+ { U64 const randomID = XXH64((char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, 0);
+ U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;
+ U32 const dictID = params.dictID ? params.dictID : compliantID;
+ MEM_writeLE32((char*)dictBuffer+4, dictID);
+ }
+
+ if (hSize + dictContentSize < dictBufferCapacity)
+ memmove((char*)dictBuffer + hSize, (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize);
+ return MIN(dictBufferCapacity, hSize+dictContentSize);
+}
+
+/* Hidden declaration for dbio.c */
+size_t ZDICT_trainFromBuffer_unsafe_legacy(
+ void* dictBuffer, size_t maxDictSize,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_legacy_params_t params);
+/*! ZDICT_trainFromBuffer_unsafe_legacy() :
+* Warning : `samplesBuffer` must be followed by noisy guard band.
+* @return : size of dictionary, or an error code which can be tested with ZDICT_isError()
+*/
+size_t ZDICT_trainFromBuffer_unsafe_legacy(
+ void* dictBuffer, size_t maxDictSize,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_legacy_params_t params)
+{
+ U32 const dictListSize = MAX(MAX(DICTLISTSIZE_DEFAULT, nbSamples), (U32)(maxDictSize/16));
+ dictItem* const dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList));
+ unsigned const selectivity = params.selectivityLevel == 0 ? g_selectivity_default : params.selectivityLevel;
+ unsigned const minRep = (selectivity > 30) ? MINRATIO : nbSamples >> selectivity;
+ size_t const targetDictSize = maxDictSize;
+ size_t const samplesBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);
+ size_t dictSize = 0;
+ U32 const notificationLevel = params.zParams.notificationLevel;
+
+ /* checks */
+ if (!dictList) return ERROR(memory_allocation);
+ if (maxDictSize < ZDICT_DICTSIZE_MIN) { free(dictList); return ERROR(dstSize_tooSmall); } /* requested dictionary size is too small */
+ if (samplesBuffSize < ZDICT_MIN_SAMPLES_SIZE) { free(dictList); return ERROR(dictionaryCreation_failed); } /* not enough source to create dictionary */
+
+ /* init */
+ ZDICT_initDictItem(dictList);
+
+ /* build dictionary */
+ ZDICT_trainBuffer_legacy(dictList, dictListSize,
+ samplesBuffer, samplesBuffSize,
+ samplesSizes, nbSamples,
+ minRep, notificationLevel);
+
+ /* display best matches */
+ if (params.zParams.notificationLevel>= 3) {
+ unsigned const nb = MIN(25, dictList[0].pos);
+ unsigned const dictContentSize = ZDICT_dictSize(dictList);
+ unsigned u;
+ DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", (unsigned)dictList[0].pos-1, dictContentSize);
+ DISPLAYLEVEL(3, "list %u best segments \n", nb-1);
+ for (u=1; u<nb; u++) {
+ unsigned const pos = dictList[u].pos;
+ unsigned const length = dictList[u].length;
+ U32 const printedLength = MIN(40, length);
+ if ((pos > samplesBuffSize) || ((pos + length) > samplesBuffSize)) {
+ free(dictList);
+ return ERROR(GENERIC); /* should never happen */
+ }
+ DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |",
+ u, length, pos, (unsigned)dictList[u].savings);
+ ZDICT_printHex((const char*)samplesBuffer+pos, printedLength);
+ DISPLAYLEVEL(3, "| \n");
+ } }
+
+
+ /* create dictionary */
+ { unsigned dictContentSize = ZDICT_dictSize(dictList);
+ if (dictContentSize < ZDICT_CONTENTSIZE_MIN) { free(dictList); return ERROR(dictionaryCreation_failed); } /* dictionary content too small */
+ if (dictContentSize < targetDictSize/4) {
+ DISPLAYLEVEL(2, "! warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (unsigned)maxDictSize);
+ if (samplesBuffSize < 10 * targetDictSize)
+ DISPLAYLEVEL(2, "! consider increasing the number of samples (total size : %u MB)\n", (unsigned)(samplesBuffSize>>20));
+ if (minRep > MINRATIO) {
+ DISPLAYLEVEL(2, "! consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1);
+ DISPLAYLEVEL(2, "! note : larger dictionaries are not necessarily better, test its efficiency on samples \n");
+ }
+ }
+
+ if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) {
+ unsigned proposedSelectivity = selectivity-1;
+ while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; }
+ DISPLAYLEVEL(2, "! note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (unsigned)maxDictSize);
+ DISPLAYLEVEL(2, "! consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity);
+ DISPLAYLEVEL(2, "! always test dictionary efficiency on real samples \n");
+ }
+
+ /* limit dictionary size */
+ { U32 const max = dictList->pos; /* convention : nb of useful elts within dictList */
+ U32 currentSize = 0;
+ U32 n; for (n=1; n<max; n++) {
+ currentSize += dictList[n].length;
+ if (currentSize > targetDictSize) { currentSize -= dictList[n].length; break; }
+ }
+ dictList->pos = n;
+ dictContentSize = currentSize;
+ }
+
+ /* build dict content */
+ { U32 u;
+ BYTE* ptr = (BYTE*)dictBuffer + maxDictSize;
+ for (u=1; u<dictList->pos; u++) {
+ U32 l = dictList[u].length;
+ ptr -= l;
+ if (ptr<(BYTE*)dictBuffer) { free(dictList); return ERROR(GENERIC); } /* should not happen */
+ memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l);
+ } }
+
+ dictSize = ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, maxDictSize,
+ samplesBuffer, samplesSizes, nbSamples,
+ params.zParams);
+ }
+
+ /* clean up */
+ free(dictList);
+ return dictSize;
+}
+
+
+/* ZDICT_trainFromBuffer_legacy() :
+ * issue : samplesBuffer need to be followed by a noisy guard band.
+ * work around : duplicate the buffer, and add the noise */
+size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_legacy_params_t params)
+{
+ size_t result;
+ void* newBuff;
+ size_t const sBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);
+ if (sBuffSize < ZDICT_MIN_SAMPLES_SIZE) return 0; /* not enough content => no dictionary */
+
+ newBuff = malloc(sBuffSize + NOISELENGTH);
+ if (!newBuff) return ERROR(memory_allocation);
+
+ memcpy(newBuff, samplesBuffer, sBuffSize);
+ ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH); /* guard band, for end of buffer condition */
+
+ result =
+ ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, dictBufferCapacity, newBuff,
+ samplesSizes, nbSamples, params);
+ free(newBuff);
+ return result;
+}
+
+
+size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
+{
+ ZDICT_fastCover_params_t params;
+ DEBUGLOG(3, "ZDICT_trainFromBuffer");
+ memset(&params, 0, sizeof(params));
+ params.d = 8;
+ params.steps = 4;
+ /* Default to level 6 since no compression level information is available */
+ params.zParams.compressionLevel = 3;
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1)
+ params.zParams.notificationLevel = DEBUGLEVEL;
+#endif
+ return ZDICT_optimizeTrainFromBuffer_fastCover(dictBuffer, dictBufferCapacity,
+ samplesBuffer, samplesSizes, nbSamples,
+ &params);
+}
+
+size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
+{
+ ZDICT_params_t params;
+ memset(&params, 0, sizeof(params));
+ return ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, dictBufferCapacity,
+ samplesBuffer, samplesSizes, nbSamples,
+ params);
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/zdict.h b/Utilities/cmzstd/lib/dictBuilder/zdict.h
new file mode 100644
index 000000000..d57d59f01
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/zdict.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef DICTBUILDER_H_001
+#define DICTBUILDER_H_001
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*====== Dependencies ======*/
+#include <stddef.h> /* size_t */
+
+
+/* ===== ZDICTLIB_API : control library symbols visibility ===== */
+#ifndef ZDICTLIB_VISIBILITY
+# if defined(__GNUC__) && (__GNUC__ >= 4)
+# define ZDICTLIB_VISIBILITY __attribute__ ((visibility ("default")))
+# else
+# define ZDICTLIB_VISIBILITY
+# endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define ZDICTLIB_API ZDICTLIB_VISIBILITY
+#endif
+
+
+/*! ZDICT_trainFromBuffer():
+ * Train a dictionary from an array of samples.
+ * Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4,
+ * f=20, and accel=1.
+ * Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ * The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * Note: ZDICT_trainFromBuffer() requires about 9 bytes of memory for each input byte.
+ * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ * In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ * It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer,
+ const size_t* samplesSizes, unsigned nbSamples);
+
+
+/*====== Helper functions ======*/
+ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */
+ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode);
+ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode);
+
+
+
+#ifdef ZDICT_STATIC_LINKING_ONLY
+
+/* ====================================================================================
+ * The definitions in this section are considered experimental.
+ * They should never be used with a dynamic library, as they may change in the future.
+ * They are provided for advanced usages.
+ * Use them only in association with static linking.
+ * ==================================================================================== */
+
+typedef struct {
+ int compressionLevel; /* optimize for a specific zstd compression level; 0 means default */
+ unsigned notificationLevel; /* Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */
+ unsigned dictID; /* force dictID value; 0 means auto mode (32-bits random value) */
+} ZDICT_params_t;
+
+/*! ZDICT_cover_params_t:
+ * k and d are the only required parameters.
+ * For others, value 0 means default.
+ */
+typedef struct {
+ unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
+ unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */
+ unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */
+ unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */
+ double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */
+ ZDICT_params_t zParams;
+} ZDICT_cover_params_t;
+
+typedef struct {
+ unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
+ unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */
+ unsigned f; /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/
+ unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */
+ unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */
+ double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */
+ unsigned accel; /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */
+ ZDICT_params_t zParams;
+} ZDICT_fastCover_params_t;
+
+/*! ZDICT_trainFromBuffer_cover():
+ * Train a dictionary from an array of samples using the COVER algorithm.
+ * Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ * The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte.
+ * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ * In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ * It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
+ void *dictBuffer, size_t dictBufferCapacity,
+ const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t parameters);
+
+/*! ZDICT_optimizeTrainFromBuffer_cover():
+ * The same requirements as above hold for all the parameters except `parameters`.
+ * This function tries many parameter combinations and picks the best parameters.
+ * `*parameters` is filled with the best parameters found,
+ * dictionary constructed with those parameters is stored in `dictBuffer`.
+ *
+ * All of the parameters d, k, steps are optional.
+ * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}.
+ * if steps is zero it defaults to its default value.
+ * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000].
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * On success `*parameters` contains the parameters selected.
+ * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread.
+ */
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
+ void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t* parameters);
+
+/*! ZDICT_trainFromBuffer_fastCover():
+ * Train a dictionary from an array of samples using a modified version of COVER algorithm.
+ * Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ * d and k are required.
+ * All other parameters are optional, will use default values if not provided
+ * The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * Note: ZDICT_trainFromBuffer_fastCover() requires about 1 bytes of memory for each input byte and additionally another 6 * 2^f bytes of memory .
+ * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ * In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ * It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer,
+ size_t dictBufferCapacity, const void *samplesBuffer,
+ const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_fastCover_params_t parameters);
+
+/*! ZDICT_optimizeTrainFromBuffer_fastCover():
+ * The same requirements as above hold for all the parameters except `parameters`.
+ * This function tries many parameter combinations (specifically, k and d combinations)
+ * and picks the best parameters. `*parameters` is filled with the best parameters found,
+ * dictionary constructed with those parameters is stored in `dictBuffer`.
+ * All of the parameters d, k, steps, f, and accel are optional.
+ * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}.
+ * if steps is zero it defaults to its default value.
+ * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000].
+ * If f is zero, default value of 20 is used.
+ * If accel is zero, default value of 1 is used.
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * On success `*parameters` contains the parameters selected.
+ * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 1 byte of memory for each input byte and additionally another 6 * 2^f bytes of memory for each thread.
+ */
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer,
+ size_t dictBufferCapacity, const void* samplesBuffer,
+ const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_fastCover_params_t* parameters);
+
+/*! ZDICT_finalizeDictionary():
+ * Given a custom content as a basis for dictionary, and a set of samples,
+ * finalize dictionary by adding headers and statistics.
+ *
+ * Samples must be stored concatenated in a flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample in order.
+ *
+ * dictContentSize must be >= ZDICT_CONTENTSIZE_MIN bytes.
+ * maxDictSize must be >= dictContentSize, and must be >= ZDICT_DICTSIZE_MIN bytes.
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`),
+ * or an error code, which can be tested by ZDICT_isError().
+ * Note: ZDICT_finalizeDictionary() will push notifications into stderr if instructed to, using notificationLevel>0.
+ * Note 2: dictBuffer and dictContent can overlap
+ */
+#define ZDICT_CONTENTSIZE_MIN 128
+#define ZDICT_DICTSIZE_MIN 256
+ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
+ const void* dictContent, size_t dictContentSize,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_params_t parameters);
+
+typedef struct {
+ unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */
+ ZDICT_params_t zParams;
+} ZDICT_legacy_params_t;
+
+/*! ZDICT_trainFromBuffer_legacy():
+ * Train a dictionary from an array of samples.
+ * Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ * The resulting dictionary will be saved into `dictBuffer`.
+ * `parameters` is optional and can be provided with values set to 0 to mean "default".
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ * or an error code, which can be tested with ZDICT_isError().
+ * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ * In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ * It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy(
+ void *dictBuffer, size_t dictBufferCapacity,
+ const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_legacy_params_t parameters);
+
+/* Deprecation warnings */
+/* It is generally possible to disable deprecation warnings from compiler,
+ for example with -Wno-deprecated-declarations for gcc
+ or _CRT_SECURE_NO_WARNINGS in Visual.
+ Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */
+#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS
+# define ZDICT_DEPRECATED(message) ZDICTLIB_API /* disable deprecation warnings */
+#else
+# define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+# define ZDICT_DEPRECATED(message) [[deprecated(message)]] ZDICTLIB_API
+# elif (ZDICT_GCC_VERSION >= 405) || defined(__clang__)
+# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message)))
+# elif (ZDICT_GCC_VERSION >= 301)
+# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define ZDICT_DEPRECATED(message) ZDICTLIB_API __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler")
+# define ZDICT_DEPRECATED(message) ZDICTLIB_API
+# endif
+#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */
+
+ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead")
+size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);
+
+
+#endif /* ZDICT_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* DICTBUILDER_H_001 */
diff --git a/Utilities/cmzstd/lib/zstd.h b/Utilities/cmzstd/lib/zstd.h
new file mode 100644
index 000000000..b18fc8a44
--- /dev/null
+++ b/Utilities/cmzstd/lib/zstd.h
@@ -0,0 +1,1766 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ZSTD_H_235446
+#define ZSTD_H_235446
+
+/* ====== Dependency ======*/
+#include <stddef.h> /* size_t */
+
+
+/* ===== ZSTDLIB_API : control library symbols visibility ===== */
+#ifndef ZSTDLIB_VISIBILITY
+# if defined(__GNUC__) && (__GNUC__ >= 4)
+# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default")))
+# else
+# define ZSTDLIB_VISIBILITY
+# endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define ZSTDLIB_API ZSTDLIB_VISIBILITY
+#endif
+
+
+/*******************************************************************************
+ Introduction
+
+ zstd, short for Zstandard, is a fast lossless compression algorithm, targeting
+ real-time compression scenarios at zlib-level and better compression ratios.
+ The zstd compression library provides in-memory compression and decompression
+ functions.
+
+ The library supports regular compression levels from 1 up to ZSTD_maxCLevel(),
+ which is currently 22. Levels >= 20, labeled `--ultra`, should be used with
+ caution, as they require more memory. The library also offers negative
+ compression levels, which extend the range of speed vs. ratio preferences.
+ The lower the level, the faster the speed (at the cost of compression).
+
+ Compression can be done in:
+ - a single step (described as Simple API)
+ - a single step, reusing a context (described as Explicit context)
+ - unbounded multiple steps (described as Streaming compression)
+
+ The compression ratio achievable on small data can be highly improved using
+ a dictionary. Dictionary compression can be performed in:
+ - a single step (described as Simple dictionary API)
+ - a single step, reusing a dictionary (described as Bulk-processing
+ dictionary API)
+
+ Advanced experimental functions can be accessed using
+ `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h.
+
+ Advanced experimental APIs should never be used with a dynamically-linked
+ library. They are not "stable"; their definitions or signatures may change in
+ the future. Only static linking is allowed.
+*******************************************************************************/
+
+/*------ Version ------*/
+#define ZSTD_VERSION_MAJOR 1
+#define ZSTD_VERSION_MINOR 3
+#define ZSTD_VERSION_RELEASE 8
+
+#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
+ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */
+
+#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE
+#define ZSTD_QUOTE(str) #str
+#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
+#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
+ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */
+
+/***************************************
+* Default constant
+***************************************/
+#ifndef ZSTD_CLEVEL_DEFAULT
+# define ZSTD_CLEVEL_DEFAULT 3
+#endif
+
+/***************************************
+* Simple API
+***************************************/
+/*! ZSTD_compress() :
+ * Compresses `src` content as a single zstd compressed frame into already allocated `dst`.
+ * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
+ * @return : compressed size written into `dst` (<= `dstCapacity),
+ * or an error code if it fails (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel);
+
+/*! ZSTD_decompress() :
+ * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames.
+ * `dstCapacity` is an upper bound of originalSize to regenerate.
+ * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data.
+ * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
+ * or an errorCode if it fails (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
+ const void* src, size_t compressedSize);
+
+/*! ZSTD_getFrameContentSize() : requires v1.3.0+
+ * `src` should point to the start of a ZSTD encoded frame.
+ * `srcSize` must be at least as large as the frame header.
+ * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
+ * @return : - decompressed size of `src` frame content, if known
+ * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
+ * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small)
+ * note 1 : a 0 return value means the frame is valid but "empty".
+ * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode.
+ * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
+ * In which case, it's necessary to use streaming mode to decompress data.
+ * Optionally, application can rely on some implicit limit,
+ * as ZSTD_decompress() only needs an upper bound of decompressed size.
+ * (For example, data could be necessarily cut into blocks <= 16 KB).
+ * note 3 : decompressed size is always present when compression is completed using single-pass functions,
+ * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict().
+ * note 4 : decompressed size can be very large (64-bits value),
+ * potentially larger than what local system can handle as a single memory segment.
+ * In which case, it's necessary to use streaming mode to decompress data.
+ * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified.
+ * Always ensure return value fits within application's authorized limits.
+ * Each application can set its own limits.
+ * note 6 : This function replaces ZSTD_getDecompressedSize() */
+#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
+#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2)
+ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
+
+/*! ZSTD_getDecompressedSize() :
+ * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
+ * Both functions work the same way, but ZSTD_getDecompressedSize() blends
+ * "empty", "unknown" and "error" results to the same return value (0),
+ * while ZSTD_getFrameContentSize() gives them separate return values.
+ * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
+ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
+
+
+/*====== Helper functions ======*/
+#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
+ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
+ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
+ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
+ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
+
+
+/***************************************
+* Explicit context
+***************************************/
+/*= Compression context
+ * When compressing many times,
+ * it is recommended to allocate a context just once, and re-use it for each successive compression operation.
+ * This will make workload friendlier for system's memory.
+ * Use one context per thread for parallel execution in multi-threaded environments. */
+typedef struct ZSTD_CCtx_s ZSTD_CCtx;
+ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);
+ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
+
+/*! ZSTD_compressCCtx() :
+ * Same as ZSTD_compress(), using an explicit ZSTD_CCtx
+ * The function will compress at requested compression level,
+ * ignoring any other parameter */
+ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel);
+
+/*= Decompression context
+ * When decompressing many times,
+ * it is recommended to allocate a context only once,
+ * and re-use it for each successive compression operation.
+ * This will make workload friendlier for system's memory.
+ * Use one context per thread for parallel execution. */
+typedef struct ZSTD_DCtx_s ZSTD_DCtx;
+ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);
+ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
+
+/*! ZSTD_decompressDCtx() :
+ * Same as ZSTD_decompress(),
+ * requires an allocated ZSTD_DCtx.
+ * Compatible with sticky parameters.
+ */
+ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+
+/**************************
+* Simple dictionary API
+***************************/
+/*! ZSTD_compress_usingDict() :
+ * Compression at an explicit compression level using a Dictionary.
+ * A dictionary can be any arbitrary data segment (also called a prefix),
+ * or a buffer with specified information (see dictBuilder/zdict.h).
+ * Note : This function loads the dictionary, resulting in significant startup delay.
+ * It's intended for a dictionary used only once.
+ * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */
+ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ int compressionLevel);
+
+/*! ZSTD_decompress_usingDict() :
+ * Decompression using a known Dictionary.
+ * Dictionary must be identical to the one used during compression.
+ * Note : This function loads the dictionary, resulting in significant startup delay.
+ * It's intended for a dictionary used only once.
+ * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */
+ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize);
+
+
+/***********************************
+ * Bulk processing dictionary API
+ **********************************/
+typedef struct ZSTD_CDict_s ZSTD_CDict;
+
+/*! ZSTD_createCDict() :
+ * When compressing multiple messages / blocks using the same dictionary, it's recommended to load it only once.
+ * ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup cost.
+ * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
+ * `dictBuffer` can be released after ZSTD_CDict creation, because its content is copied within CDict.
+ * Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate `dictBuffer` content.
+ * Note : A ZSTD_CDict can be created from an empty dictBuffer, but it is inefficient when used to compress small data. */
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize,
+ int compressionLevel);
+
+/*! ZSTD_freeCDict() :
+ * Function frees memory allocated by ZSTD_createCDict(). */
+ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict);
+
+/*! ZSTD_compress_usingCDict() :
+ * Compression using a digested Dictionary.
+ * Recommended when same dictionary is used multiple times.
+ * Note : compression level is _decided at dictionary creation time_,
+ * and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */
+ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict);
+
+
+typedef struct ZSTD_DDict_s ZSTD_DDict;
+
+/*! ZSTD_createDDict() :
+ * Create a digested dictionary, ready to start decompression operation without startup delay.
+ * dictBuffer can be released after DDict creation, as its content is copied inside DDict. */
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
+
+/*! ZSTD_freeDDict() :
+ * Function frees memory allocated with ZSTD_createDDict() */
+ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict);
+
+/*! ZSTD_decompress_usingDDict() :
+ * Decompression using a digested Dictionary.
+ * Recommended when same dictionary is used multiple times. */
+ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_DDict* ddict);
+
+
+/****************************
+* Streaming
+****************************/
+
+typedef struct ZSTD_inBuffer_s {
+ const void* src; /**< start of input buffer */
+ size_t size; /**< size of input buffer */
+ size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */
+} ZSTD_inBuffer;
+
+typedef struct ZSTD_outBuffer_s {
+ void* dst; /**< start of output buffer */
+ size_t size; /**< size of output buffer */
+ size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */
+} ZSTD_outBuffer;
+
+
+
+/*-***********************************************************************
+* Streaming compression - HowTo
+*
+* A ZSTD_CStream object is required to track streaming operation.
+* Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources.
+* ZSTD_CStream objects can be reused multiple times on consecutive compression operations.
+* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory.
+*
+* For parallel execution, use one separate ZSTD_CStream per thread.
+*
+* note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing.
+*
+* Parameters are sticky : when starting a new compression on the same context,
+* it will re-use the same sticky parameters as previous compression session.
+* When in doubt, it's recommended to fully initialize the context before usage.
+* Use ZSTD_initCStream() to set the parameter to a selected compression level.
+* Use advanced API (ZSTD_CCtx_setParameter(), etc.) to set more specific parameters.
+*
+* Use ZSTD_compressStream() as many times as necessary to consume input stream.
+* The function will automatically update both `pos` fields within `input` and `output`.
+* Note that the function may not consume the entire input,
+* for example, because the output buffer is already full,
+* in which case `input.pos < input.size`.
+* The caller must check if input has been entirely consumed.
+* If not, the caller must make some room to receive more compressed data,
+* and then present again remaining input data.
+* @return : a size hint, preferred nb of bytes to use as input for next function call
+* or an error code, which can be tested using ZSTD_isError().
+* Note 1 : it's just a hint, to help latency a little, any value will work fine.
+* Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()
+*
+* At any moment, it's possible to flush whatever data might remain stuck within internal buffer,
+* using ZSTD_flushStream(). `output->pos` will be updated.
+* Note that, if `output->size` is too small, a single invocation of ZSTD_flushStream() might not be enough (return code > 0).
+* In which case, make some room to receive more compressed data, and call again ZSTD_flushStream().
+* @return : 0 if internal buffers are entirely flushed,
+* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
+* or an error code, which can be tested using ZSTD_isError().
+*
+* ZSTD_endStream() instructs to finish a frame.
+* It will perform a flush and write frame epilogue.
+* The epilogue is required for decoders to consider a frame completed.
+* flush() operation is the same, and follows same rules as ZSTD_flushStream().
+* @return : 0 if frame fully completed and fully flushed,
+* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
+* or an error code, which can be tested using ZSTD_isError().
+*
+* *******************************************************************/
+
+typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */
+ /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */
+/*===== ZSTD_CStream management functions =====*/
+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);
+ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
+
+/*===== Streaming compression functions =====*/
+ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
+ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
+
+ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */
+ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */
+
+
+
+/*-***************************************************************************
+* Streaming decompression - HowTo
+*
+* A ZSTD_DStream object is required to track streaming operations.
+* Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources.
+* ZSTD_DStream objects can be re-used multiple times.
+*
+* Use ZSTD_initDStream() to start a new decompression operation.
+* @return : recommended first input size
+* Alternatively, use advanced API to set specific properties.
+*
+* Use ZSTD_decompressStream() repetitively to consume your input.
+* The function will update both `pos` fields.
+* If `input.pos < input.size`, some input has not been consumed.
+* It's up to the caller to present again remaining data.
+* The function tries to flush all data decoded immediately, respecting output buffer size.
+* If `output.pos < output.size`, decoder has flushed everything it could.
+* But if `output.pos == output.size`, there might be some data left within internal buffers.,
+* In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer.
+* Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX.
+* @return : 0 when a frame is completely decoded and fully flushed,
+* or an error code, which can be tested using ZSTD_isError(),
+* or any other value > 0, which means there is still some decoding or flushing to do to complete current frame :
+* the return value is a suggested next input size (just a hint for better latency)
+* that will never request more than the remaining frame size.
+* *******************************************************************************/
+
+typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */
+ /* For compatibility with versions <= v1.2.0, prefer differentiating them. */
+/*===== ZSTD_DStream management functions =====*/
+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
+ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
+
+/*===== Streaming decompression functions =====*/
+ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+
+ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */
+ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */
+
+#endif /* ZSTD_H_235446 */
+
+
+
+
+/****************************************************************************************
+ * ADVANCED AND EXPERIMENTAL FUNCTIONS
+ ****************************************************************************************
+ * The definitions in the following section are considered experimental.
+ * They are provided for advanced scenarios.
+ * They should never be used with a dynamic library, as prototypes may change in the future.
+ * Use them only in association with static linking.
+ * ***************************************************************************************/
+
+#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
+#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY
+
+
+/****************************************************************************************
+ * Candidate API for promotion to stable status
+ ****************************************************************************************
+ * The following symbols and constants form the "staging area" :
+ * they are considered to join "stable API" by v1.4.0.
+ * The proposal is written so that it can be made stable "as is",
+ * though it's still possible to suggest improvements.
+ * Staging is in fact last chance for changes,
+ * the API is locked once reaching "stable" status.
+ * ***************************************************************************************/
+
+
+/* === Constants === */
+
+/* all magic numbers are supposed read/written to/from files/memory using little-endian convention */
+#define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */
+#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* valid since v0.7.0 */
+#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50 /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */
+#define ZSTD_MAGIC_SKIPPABLE_MASK 0xFFFFFFF0
+
+#define ZSTD_BLOCKSIZELOG_MAX 17
+#define ZSTD_BLOCKSIZE_MAX (1<<ZSTD_BLOCKSIZELOG_MAX)
+
+
+/* === query limits === */
+
+ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */
+
+
+/* === frame size === */
+
+/*! ZSTD_findFrameCompressedSize() :
+ * `src` should point to the start of a ZSTD frame or skippable frame.
+ * `srcSize` must be >= first frame size
+ * @return : the compressed size of the first frame starting at `src`,
+ * suitable to pass as `srcSize` to `ZSTD_decompress` or similar,
+ * or an error code if input is invalid */
+ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
+
+
+/* === Memory management === */
+
+/*! ZSTD_sizeof_*() :
+ * These functions give the _current_ memory usage of selected object.
+ * Note that object memory usage can evolve (increase or decrease) over time. */
+ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
+ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
+ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
+
+
+/***************************************
+* Advanced compression API
+***************************************/
+
+/* API design :
+ * Parameters are pushed one by one into an existing context,
+ * using ZSTD_CCtx_set*() functions.
+ * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame.
+ * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` !
+ * They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()
+ *
+ * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset().
+ *
+ * This API supercedes all other "advanced" API entry points in the experimental section.
+ * In the future, we expect to remove from experimental API entry points which are redundant with this API.
+ */
+
+
+/* Compression strategies, listed from fastest to strongest */
+typedef enum { ZSTD_fast=1,
+ ZSTD_dfast=2,
+ ZSTD_greedy=3,
+ ZSTD_lazy=4,
+ ZSTD_lazy2=5,
+ ZSTD_btlazy2=6,
+ ZSTD_btopt=7,
+ ZSTD_btultra=8,
+ ZSTD_btultra2=9
+ /* note : new strategies _might_ be added in the future.
+ Only the order (from fast to strong) is guaranteed */
+} ZSTD_strategy;
+
+
+typedef enum {
+
+ /* compression parameters */
+ ZSTD_c_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
+ * Default level is ZSTD_CLEVEL_DEFAULT==3.
+ * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT.
+ * Note 1 : it's possible to pass a negative compression level.
+ * Note 2 : setting a level sets all default values of other compression parameters */
+ ZSTD_c_windowLog=101, /* Maximum allowed back-reference distance, expressed as power of 2.
+ * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
+ * Special: value 0 means "use default windowLog".
+ * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT
+ * requires explicitly allowing such window size at decompression stage if using streaming. */
+ ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2.
+ * Resulting memory usage is (1 << (hashLog+2)).
+ * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
+ * Larger tables improve compression ratio of strategies <= dFast,
+ * and improve speed of strategies > dFast.
+ * Special: value 0 means "use default hashLog". */
+ ZSTD_c_chainLog=103, /* Size of the multi-probe search table, as a power of 2.
+ * Resulting memory usage is (1 << (chainLog+2)).
+ * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX.
+ * Larger tables result in better and slower compression.
+ * This parameter is useless when using "fast" strategy.
+ * It's still useful when using "dfast" strategy,
+ * in which case it defines a secondary probe table.
+ * Special: value 0 means "use default chainLog". */
+ ZSTD_c_searchLog=104, /* Number of search attempts, as a power of 2.
+ * More attempts result in better and slower compression.
+ * This parameter is useless when using "fast" and "dFast" strategies.
+ * Special: value 0 means "use default searchLog". */
+ ZSTD_c_minMatch=105, /* Minimum size of searched matches.
+ * Note that Zstandard can still find matches of smaller size,
+ * it just tweaks its search algorithm to look for this size and larger.
+ * Larger values increase compression and decompression speed, but decrease ratio.
+ * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX.
+ * Note that currently, for all strategies < btopt, effective minimum is 4.
+ * , for all strategies > fast, effective maximum is 6.
+ * Special: value 0 means "use default minMatchLength". */
+ ZSTD_c_targetLength=106, /* Impact of this field depends on strategy.
+ * For strategies btopt, btultra & btultra2:
+ * Length of Match considered "good enough" to stop search.
+ * Larger values make compression stronger, and slower.
+ * For strategy fast:
+ * Distance between match sampling.
+ * Larger values make compression faster, and weaker.
+ * Special: value 0 means "use default targetLength". */
+ ZSTD_c_strategy=107, /* See ZSTD_strategy enum definition.
+ * The higher the value of selected strategy, the more complex it is,
+ * resulting in stronger and slower compression.
+ * Special: value 0 means "use default strategy". */
+
+ /* LDM mode parameters */
+ ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching.
+ * This parameter is designed to improve compression ratio
+ * for large inputs, by finding large matches at long distance.
+ * It increases memory usage and window size.
+ * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB
+ * except when expressly set to a different value. */
+ ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2.
+ * Larger values increase memory usage and compression ratio,
+ * but decrease compression speed.
+ * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
+ * default: windowlog - 7.
+ * Special: value 0 means "automatically determine hashlog". */
+ ZSTD_c_ldmMinMatch=162, /* Minimum match size for long distance matcher.
+ * Larger/too small values usually decrease compression ratio.
+ * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX.
+ * Special: value 0 means "use default value" (default: 64). */
+ ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution.
+ * Larger values improve collision resolution but decrease compression speed.
+ * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX.
+ * Special: value 0 means "use default value" (default: 3). */
+ ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table.
+ * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN).
+ * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage.
+ * Larger values improve compression speed.
+ * Deviating far from default value will likely result in a compression ratio decrease.
+ * Special: value 0 means "automatically determine hashRateLog". */
+
+ /* frame parameters */
+ ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1)
+ * Content size must be known at the beginning of compression.
+ * This is automatically the case when using ZSTD_compress2(),
+ * For streaming variants, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */
+ ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */
+ ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */
+
+ /* multi-threading parameters */
+ /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
+ * They return an error otherwise. */
+ ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel.
+ * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() :
+ * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller,
+ * while compression work is performed in parallel, within worker threads.
+ * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end :
+ * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call).
+ * More workers improve speed, but also increase memory usage.
+ * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
+ ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
+ * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
+ * 0 means default, which is dynamically determined based on compression parameters.
+ * Job size must be a minimum of overlap size, or 1 MB, whichever is largest.
+ * The minimum size is automatically and transparently enforced */
+ ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size.
+ * The overlap size is an amount of data reloaded from previous job at the beginning of a new job.
+ * It helps preserve compression ratio, while each job is compressed in parallel.
+ * This value is enforced only when nbWorkers >= 1.
+ * Larger values increase compression ratio, but decrease speed.
+ * Possible values range from 0 to 9 :
+ * - 0 means "default" : value will be determined by the library, depending on strategy
+ * - 1 means "no overlap"
+ * - 9 means "full overlap", using a full window size.
+ * Each intermediate rank increases/decreases load size by a factor 2 :
+ * 9: full window; 8: w/2; 7: w/4; 6: w/8; 5:w/16; 4: w/32; 3:w/64; 2:w/128; 1:no overlap; 0:default
+ * default value varies between 6 and 9, depending on strategy */
+
+ /* note : additional experimental parameters are also available
+ * within the experimental section of the API.
+ * At the time of this writing, they include :
+ * ZSTD_c_rsyncable
+ * ZSTD_c_format
+ * ZSTD_c_forceMaxWindow
+ * ZSTD_c_forceAttachDict
+ * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
+ * note : never ever use experimentalParam? names directly;
+ * also, the enums values themselves are unstable and can still change.
+ */
+ ZSTD_c_experimentalParam1=500,
+ ZSTD_c_experimentalParam2=10,
+ ZSTD_c_experimentalParam3=1000,
+ ZSTD_c_experimentalParam4=1001
+} ZSTD_cParameter;
+
+
+typedef struct {
+ size_t error;
+ int lowerBound;
+ int upperBound;
+} ZSTD_bounds;
+
+/*! ZSTD_cParam_getBounds() :
+ * All parameters must belong to an interval with lower and upper bounds,
+ * otherwise they will either trigger an error or be automatically clamped.
+ * @return : a structure, ZSTD_bounds, which contains
+ * - an error status field, which must be tested using ZSTD_isError()
+ * - lower and upper bounds, both inclusive
+ */
+ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam);
+
+/*! ZSTD_CCtx_setParameter() :
+ * Set one compression parameter, selected by enum ZSTD_cParameter.
+ * All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds().
+ * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
+ * Setting a parameter is generally only possible during frame initialization (before starting compression).
+ * Exception : when using multi-threading mode (nbWorkers >= 1),
+ * the following parameters can be updated _during_ compression (within same frame):
+ * => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
+ * new parameters will be active for next job only (after a flush()).
+ * @return : an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value);
+
+/*! ZSTD_CCtx_setPledgedSrcSize() :
+ * Total input data size to be compressed as a single frame.
+ * Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag.
+ * This value will also be controlled at end of frame, and trigger an error if not respected.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame.
+ * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN.
+ * ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame.
+ * Note 2 : pledgedSrcSize is only valid once, for the next frame.
+ * It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN.
+ * Note 3 : Whenever all input data is provided and consumed in a single round,
+ * for example with ZSTD_compress2(),
+ * or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end),
+ * this value is automatically overriden by srcSize instead.
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
+
+/*! ZSTD_CCtx_loadDictionary() :
+ * Create an internal CDict from `dict` buffer.
+ * Decompression will have to use same dictionary.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary,
+ * meaning "return to no-dictionary mode".
+ * Note 1 : Dictionary is sticky, it will be used for all future compressed frames.
+ * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters).
+ * Note 2 : Loading a dictionary involves building tables.
+ * It's also a CPU consuming operation, with non-negligible impact on latency.
+ * Tables are dependent on compression parameters, and for this reason,
+ * compression parameters can no longer be changed after loading a dictionary.
+ * Note 3 :`dict` content will be copied internally.
+ * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead.
+ * In such a case, dictionary buffer must outlive its users.
+ * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
+ * to precisely select how dictionary content must be interpreted. */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_CCtx_refCDict() :
+ * Reference a prepared dictionary, to be used for all next compressed frames.
+ * Note that compression parameters are enforced from within CDict,
+ * and supercede any compression parameter previously set within CCtx.
+ * The dictionary will remain valid for future compressed frames using same CCtx.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Special : Referencing a NULL CDict means "return to no-dictionary mode".
+ * Note 1 : Currently, only one dictionary can be managed.
+ * Referencing a new dictionary effectively "discards" any previous one.
+ * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */
+ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
+
+/*! ZSTD_CCtx_refPrefix() :
+ * Reference a prefix (single-usage dictionary) for next compressed frame.
+ * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end).
+ * Decompression will need same prefix to properly regenerate data.
+ * Compressing with a prefix is similar in outcome as performing a diff and compressing it,
+ * but performs much faster, especially during decompression (compression speed is tunable with compression level).
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
+ * Note 1 : Prefix buffer is referenced. It **must** outlive compression.
+ * Its content must remain unmodified during compression.
+ * Note 2 : If the intention is to diff some large src data blob with some prior version of itself,
+ * ensure that the window size is large enough to contain the entire source.
+ * See ZSTD_c_windowLog.
+ * Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters.
+ * It's a CPU consuming operation, with non-negligible impact on latency.
+ * If there is a need to use the same prefix multiple times, consider loadDictionary instead.
+ * Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dm_rawContent).
+ * Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */
+ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
+ const void* prefix, size_t prefixSize);
+
+
+typedef enum {
+ ZSTD_reset_session_only = 1,
+ ZSTD_reset_parameters = 2,
+ ZSTD_reset_session_and_parameters = 3
+} ZSTD_ResetDirective;
+
+/*! ZSTD_CCtx_reset() :
+ * There are 2 different things that can be reset, independently or jointly :
+ * - The session : will stop compressing current frame, and make CCtx ready to start a new one.
+ * Useful after an error, or to interrupt any ongoing compression.
+ * Any internal data not yet flushed is cancelled.
+ * Compression parameters and dictionary remain unchanged.
+ * They will be used to compress next frame.
+ * Resetting session never fails.
+ * - The parameters : changes all parameters back to "default".
+ * This removes any reference to any dictionary too.
+ * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing)
+ * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError())
+ * - Both : similar to resetting the session, followed by resetting parameters.
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset);
+
+
+
+/*! ZSTD_compress2() :
+ * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API.
+ * ZSTD_compress2() always starts a new frame.
+ * Should cctx hold data from a previously unfinished frame, everything about it is forgotten.
+ * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
+ * - The function is always blocking, returns when compression is completed.
+ * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
+ * @return : compressed size written into `dst` (<= `dstCapacity),
+ * or an error code if it fails (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+typedef enum {
+ ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */
+ ZSTD_e_flush=1, /* flush any data provided so far,
+ * it creates (at least) one new block, that can be decoded immediately on reception;
+ * frame will continue: any future data can still reference previously compressed data, improving compression. */
+ ZSTD_e_end=2 /* flush any remaining data _and_ close current frame.
+ * note that frame is only closed after compressed data is fully flushed (return value == 0).
+ * After that point, any additional data starts a new frame.
+ * note : each frame is independent (does not reference any content from previous frame). */
+} ZSTD_EndDirective;
+
+/*! ZSTD_compressStream2() :
+ * Behaves about the same as ZSTD_compressStream, with additional control on end directive.
+ * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
+ * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode)
+ * - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
+ * - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
+ * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller.
+ * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available,
+ * and then immediately returns, just indicating that there is some data remaining to be flushed.
+ * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
+ * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking.
+ * - @return provides a minimum amount of data remaining to be flushed from internal buffers
+ * or an error code, which can be tested using ZSTD_isError().
+ * if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
+ * This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers.
+ * For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed.
+ * - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
+ * only ZSTD_e_end or ZSTD_e_flush operations are allowed.
+ * Before starting a new compression job, or changing compression parameters,
+ * it is required to fully flush internal buffers.
+ */
+ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective endOp);
+
+
+
+/* ============================== */
+/* Advanced decompression API */
+/* ============================== */
+
+/* The advanced API pushes parameters one by one into an existing DCtx context.
+ * Parameters are sticky, and remain valid for all following frames
+ * using the same DCtx context.
+ * It's possible to reset parameters to default values using ZSTD_DCtx_reset().
+ * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream().
+ * Therefore, no new decompression function is necessary.
+ */
+
+
+typedef enum {
+
+ ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which
+ * the streaming API will refuse to allocate memory buffer
+ * in order to protect the host from unreasonable memory requirements.
+ * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
+ * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) */
+
+ /* note : additional experimental parameters are also available
+ * within the experimental section of the API.
+ * At the time of this writing, they include :
+ * ZSTD_c_format
+ * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
+ * note : never ever use experimentalParam? names directly
+ */
+ ZSTD_d_experimentalParam1=1000
+
+} ZSTD_dParameter;
+
+
+/*! ZSTD_dParam_getBounds() :
+ * All parameters must belong to an interval with lower and upper bounds,
+ * otherwise they will either trigger an error or be automatically clamped.
+ * @return : a structure, ZSTD_bounds, which contains
+ * - an error status field, which must be tested using ZSTD_isError()
+ * - both lower and upper bounds, inclusive
+ */
+ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam);
+
+/*! ZSTD_DCtx_setParameter() :
+ * Set one compression parameter, selected by enum ZSTD_dParameter.
+ * All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds().
+ * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
+ * Setting a parameter is only possible during frame initialization (before starting decompression).
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value);
+
+
+/*! ZSTD_DCtx_loadDictionary() :
+ * Create an internal DDict from dict buffer,
+ * to be used to decompress next frames.
+ * The dictionary remains valid for all future frames, until explicitly invalidated.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
+ * meaning "return to no-dictionary mode".
+ * Note 1 : Loading a dictionary involves building tables,
+ * which has a non-negligible impact on CPU usage and latency.
+ * It's recommended to "load once, use many times", to amortize the cost
+ * Note 2 :`dict` content will be copied internally, so `dict` can be released after loading.
+ * Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead.
+ * Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of
+ * how dictionary content is loaded and interpreted.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_DCtx_refDDict() :
+ * Reference a prepared dictionary, to be used to decompress next frames.
+ * The dictionary remains active for decompression of future frames using same DCtx.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Note 1 : Currently, only one dictionary can be managed.
+ * Referencing a new dictionary effectively "discards" any previous one.
+ * Special: referencing a NULL DDict means "return to no-dictionary mode".
+ * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+/*! ZSTD_DCtx_refPrefix() :
+ * Reference a prefix (single-usage dictionary) to decompress next frame.
+ * This is the reverse operation of ZSTD_CCtx_refPrefix(),
+ * and must use the same prefix as the one used during compression.
+ * Prefix is **only used once**. Reference is discarded at end of frame.
+ * End of frame is reached when ZSTD_decompressStream() returns 0.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ * Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
+ * Note 2 : Prefix buffer is referenced. It **must** outlive decompression.
+ * Prefix buffer must remain unmodified up to the end of frame,
+ * reached when ZSTD_decompressStream() returns 0.
+ * Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
+ * Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section)
+ * Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
+ * A full dictionary is more costly, as it requires building tables.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx,
+ const void* prefix, size_t prefixSize);
+
+/*! ZSTD_DCtx_reset() :
+ * Return a DCtx to clean state.
+ * Session and parameters can be reset jointly or separately.
+ * Parameters can only be reset when no active frame is being decompressed.
+ * @return : 0, or an error code, which can be tested with ZSTD_isError()
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset);
+
+
+
+/****************************************************************************************
+ * experimental API (static linking only)
+ ****************************************************************************************
+ * The following symbols and constants
+ * are not planned to join "stable API" status in the near future.
+ * They can still change in future versions.
+ * Some of them are planned to remain in the static_only section indefinitely.
+ * Some of them might be removed in the future (especially when redundant with existing stable functions)
+ * ***************************************************************************************/
+
+#define ZSTD_FRAMEHEADERSIZE_PREFIX 5 /* minimum input size required to query frame header size */
+#define ZSTD_FRAMEHEADERSIZE_MIN 6
+#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */
+#define ZSTD_SKIPPABLEHEADERSIZE 8
+
+/* compression parameter bounds */
+#define ZSTD_WINDOWLOG_MAX_32 30
+#define ZSTD_WINDOWLOG_MAX_64 31
+#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
+#define ZSTD_WINDOWLOG_MIN 10
+#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30)
+#define ZSTD_HASHLOG_MIN 6
+#define ZSTD_CHAINLOG_MAX_32 29
+#define ZSTD_CHAINLOG_MAX_64 30
+#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64))
+#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
+#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
+#define ZSTD_SEARCHLOG_MIN 1
+#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
+#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */
+#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX
+#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */
+#define ZSTD_STRATEGY_MIN ZSTD_fast
+#define ZSTD_STRATEGY_MAX ZSTD_btultra2
+
+
+#define ZSTD_OVERLAPLOG_MIN 0
+#define ZSTD_OVERLAPLOG_MAX 9
+
+#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame
+ * requiring larger than (1<<ZSTD_WINDOWLOG_LIMIT_DEFAULT) window size,
+ * to preserve host's memory from unreasonable requirements.
+ * This limit can be overriden using ZSTD_DCtx_setParameter(,ZSTD_d_windowLogMax,).
+ * The limit does not apply for one-pass decoders (such as ZSTD_decompress()), since no additional memory is allocated */
+
+
+/* LDM parameter bounds */
+#define ZSTD_LDM_HASHLOG_MIN ZSTD_HASHLOG_MIN
+#define ZSTD_LDM_HASHLOG_MAX ZSTD_HASHLOG_MAX
+#define ZSTD_LDM_MINMATCH_MIN 4
+#define ZSTD_LDM_MINMATCH_MAX 4096
+#define ZSTD_LDM_BUCKETSIZELOG_MIN 1
+#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
+#define ZSTD_LDM_HASHRATELOG_MIN 0
+#define ZSTD_LDM_HASHRATELOG_MAX (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
+
+/* internal */
+#define ZSTD_HASHLOG3_MAX 17
+
+
+/* --- Advanced types --- */
+
+typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
+
+typedef struct {
+ unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */
+ unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */
+ unsigned hashLog; /**< dispatch table : larger == faster, more memory */
+ unsigned searchLog; /**< nb of searches : larger == more compression, slower */
+ unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */
+ unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */
+ ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */
+} ZSTD_compressionParameters;
+
+typedef struct {
+ int contentSizeFlag; /**< 1: content size will be in frame header (when known) */
+ int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */
+ int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */
+} ZSTD_frameParameters;
+
+typedef struct {
+ ZSTD_compressionParameters cParams;
+ ZSTD_frameParameters fParams;
+} ZSTD_parameters;
+
+typedef enum {
+ ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
+ ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
+ ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */
+} ZSTD_dictContentType_e;
+
+typedef enum {
+ ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
+ ZSTD_dlm_byRef = 1, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
+} ZSTD_dictLoadMethod_e;
+
+typedef enum {
+ /* Opened question : should we have a format ZSTD_f_auto ?
+ * Today, it would mean exactly the same as ZSTD_f_zstd1.
+ * But, in the future, should several formats become supported,
+ * on the compression side, it would mean "default format".
+ * On the decompression side, it would mean "automatic format detection",
+ * so that ZSTD_f_zstd1 would mean "accept *only* zstd frames".
+ * Since meaning is a little different, another option could be to define different enums for compression and decompression.
+ * This question could be kept for later, when there are actually multiple formats to support,
+ * but there is also the question of pinning enum values, and pinning value `0` is especially important */
+ ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */
+ ZSTD_f_zstd1_magicless = 1, /* Variant of zstd frame format, without initial 4-bytes magic number.
+ * Useful to save 4 bytes per generated frame.
+ * Decoder cannot recognise automatically this format, requiring this instruction. */
+} ZSTD_format_e;
+
+typedef enum {
+ /* Note: this enum and the behavior it controls are effectively internal
+ * implementation details of the compressor. They are expected to continue
+ * to evolve and should be considered only in the context of extremely
+ * advanced performance tuning.
+ *
+ * Zstd currently supports the use of a CDict in two ways:
+ *
+ * - The contents of the CDict can be copied into the working context. This
+ * means that the compression can search both the dictionary and input
+ * while operating on a single set of internal tables. This makes
+ * the compression faster per-byte of input. However, the initial copy of
+ * the CDict's tables incurs a fixed cost at the beginning of the
+ * compression. For small compressions (< 8 KB), that copy can dominate
+ * the cost of the compression.
+ *
+ * - The CDict's tables can be used in-place. In this model, compression is
+ * slower per input byte, because the compressor has to search two sets of
+ * tables. However, this model incurs no start-up cost (as long as the
+ * working context's tables can be reused). For small inputs, this can be
+ * faster than copying the CDict's tables.
+ *
+ * Zstd has a simple internal heuristic that selects which strategy to use
+ * at the beginning of a compression. However, if experimentation shows that
+ * Zstd is making poor choices, it is possible to override that choice with
+ * this enum.
+ */
+ ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */
+ ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */
+ ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */
+} ZSTD_dictAttachPref_e;
+
+
+/***************************************
+* Frame size functions
+***************************************/
+
+/*! ZSTD_findDecompressedSize() :
+ * `src` should point the start of a series of ZSTD encoded and/or skippable frames
+ * `srcSize` must be the _exact_ size of this series
+ * (i.e. there should be a frame boundary exactly at `srcSize` bytes after `src`)
+ * @return : - decompressed size of all data in all successive frames
+ * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN
+ * - if an error occurred: ZSTD_CONTENTSIZE_ERROR
+ *
+ * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode.
+ * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
+ * In which case, it's necessary to use streaming mode to decompress data.
+ * note 2 : decompressed size is always present when compression is done with ZSTD_compress()
+ * note 3 : decompressed size can be very large (64-bits value),
+ * potentially larger than what local system can handle as a single memory segment.
+ * In which case, it's necessary to use streaming mode to decompress data.
+ * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified.
+ * Always ensure result fits within application's authorized limits.
+ * Each application can set its own limits.
+ * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to
+ * read each contained frame header. This is fast as most of the data is skipped,
+ * however it does mean that all frame data must be present and valid. */
+ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
+
+/*! ZSTD_frameHeaderSize() :
+ * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * @return : size of the Frame Header,
+ * or an error code (if srcSize is too small) */
+ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
+
+
+/***************************************
+* Memory management
+***************************************/
+
+/*! ZSTD_estimate*() :
+ * These functions make it possible to estimate memory usage
+ * of a future {D,C}Ctx, before its creation.
+ * ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
+ * It will also consider src size to be arbitrarily "large", which is worst case.
+ * If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
+ * ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
+ * ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
+ * Note : CCtx size estimation is only correct for single-threaded compression. */
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
+
+/*! ZSTD_estimateCStreamSize() :
+ * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
+ * It will also consider src size to be arbitrarily "large", which is worst case.
+ * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
+ * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
+ * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
+ * Note : CStream size estimation is only correct for single-threaded compression.
+ * ZSTD_DStream memory budget depends on window Size.
+ * This information can be passed manually, using ZSTD_estimateDStreamSize,
+ * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
+ * Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
+ * an internal ?Dict will be created, which additional size is not estimated here.
+ * In this case, get total size by adding ZSTD_estimate?DictSize */
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
+ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
+
+/*! ZSTD_estimate?DictSize() :
+ * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
+ * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced().
+ * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller.
+ */
+ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
+ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
+
+/*! ZSTD_initStatic*() :
+ * Initialize an object using a pre-allocated fixed-size buffer.
+ * workspace: The memory area to emplace the object into.
+ * Provided pointer *must be 8-bytes aligned*.
+ * Buffer must outlive object.
+ * workspaceSize: Use ZSTD_estimate*Size() to determine
+ * how large workspace must be to support target scenario.
+ * @return : pointer to object (same address as workspace, just different type),
+ * or NULL if error (size too small, incorrect alignment, etc.)
+ * Note : zstd will never resize nor malloc() when using a static buffer.
+ * If the object requires more memory than available,
+ * zstd will just error out (typically ZSTD_error_memory_allocation).
+ * Note 2 : there is no corresponding "free" function.
+ * Since workspace is allocated externally, it must be freed externally too.
+ * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
+ * into its associated cParams.
+ * Limitation 1 : currently not compatible with internal dictionary creation, triggered by
+ * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict().
+ * Limitation 2 : static cctx currently not compatible with multi-threading.
+ * Limitation 3 : static dctx is incompatible with legacy support.
+ */
+ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
+ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
+
+ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
+ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */
+
+ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict(
+ void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams);
+
+ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict(
+ void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType);
+
+
+/*! Custom memory allocation :
+ * These prototypes make it possible to pass your own allocation/free functions.
+ * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below.
+ * All allocation/free operations will be completed using these custom variants instead of regular <stdlib.h> ones.
+ */
+typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
+typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
+typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
+static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */
+
+ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams,
+ ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_customMem customMem);
+
+
+
+/***************************************
+* Advanced compression functions
+***************************************/
+
+/*! ZSTD_createCDict_byReference() :
+ * Create a digested dictionary for compression
+ * Dictionary content is just referenced, not duplicated.
+ * As a consequence, `dictBuffer` **must** outlive CDict,
+ * and its content must remain unmodified throughout the lifetime of CDict. */
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
+
+/*! ZSTD_getCParams() :
+* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
+* `estimatedSrcSize` value is optional, select 0 if not known */
+ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
+
+/*! ZSTD_getParams() :
+* same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
+* All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */
+ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
+
+/*! ZSTD_checkCParams() :
+* Ensure param values remain within authorized range */
+ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params);
+
+/*! ZSTD_adjustCParams() :
+ * optimize params for a given `srcSize` and `dictSize`.
+ * both values are optional, select `0` if unknown. */
+ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize);
+
+/*! ZSTD_compress_advanced() :
+ * Same as ZSTD_compress_usingDict(), with fine-tune control over compression parameters (by structure) */
+ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_parameters params);
+
+/*! ZSTD_compress_usingCDict_advanced() :
+ * Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters */
+ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict,
+ ZSTD_frameParameters fParams);
+
+
+/*! ZSTD_CCtx_loadDictionary_byReference() :
+ * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx.
+ * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_CCtx_loadDictionary_advanced() :
+ * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over
+ * how to load the dictionary (by copy ? by reference ?)
+ * and how to interpret it (automatic ? force raw mode ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_CCtx_refPrefix_advanced() :
+ * Same as ZSTD_CCtx_refPrefix(), but gives finer control over
+ * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
+
+/* === experimental parameters === */
+/* these parameters can be used with ZSTD_setParameter()
+ * they are not guaranteed to remain supported in the future */
+
+ /* Enables rsyncable mode,
+ * which makes compressed files more rsync friendly
+ * by adding periodic synchronization points to the compressed data.
+ * The target average block size is ZSTD_c_jobSize / 2.
+ * It's possible to modify the job size to increase or decrease
+ * the granularity of the synchronization point.
+ * Once the jobSize is smaller than the window size,
+ * it will result in compression ratio degradation.
+ * NOTE 1: rsyncable mode only works when multithreading is enabled.
+ * NOTE 2: rsyncable performs poorly in combination with long range mode,
+ * since it will decrease the effectiveness of synchronization points,
+ * though mileage may vary.
+ * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s.
+ * If the selected compression level is already running significantly slower,
+ * the overall speed won't be significantly impacted.
+ */
+ #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1
+
+/* Select a compression format.
+ * The value must be of type ZSTD_format_e.
+ * See ZSTD_format_e enum definition for details */
+#define ZSTD_c_format ZSTD_c_experimentalParam2
+
+/* Force back-reference distances to remain < windowSize,
+ * even when referencing into Dictionary content (default:0) */
+#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3
+
+/* Controls whether the contents of a CDict
+ * are used in place, or copied into the working context.
+ * Accepts values from the ZSTD_dictAttachPref_e enum.
+ * See the comments on that enum for an explanation of the feature. */
+#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4
+
+/*! ZSTD_CCtx_getParameter() :
+ * Get the requested compression parameter value, selected by enum ZSTD_cParameter,
+ * and store it into int* value.
+ * @return : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
+
+
+/*! ZSTD_CCtx_params :
+ * Quick howto :
+ * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
+ * - ZSTD_CCtxParam_setParameter() : Push parameters one by one into
+ * an existing ZSTD_CCtx_params structure.
+ * This is similar to
+ * ZSTD_CCtx_setParameter().
+ * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
+ * an existing CCtx.
+ * These parameters will be applied to
+ * all subsequent frames.
+ * - ZSTD_compressStream2() : Do compression using the CCtx.
+ * - ZSTD_freeCCtxParams() : Free the memory.
+ *
+ * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
+ * for static allocation of CCtx for single-threaded compression.
+ */
+ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
+ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
+
+/*! ZSTD_CCtxParams_reset() :
+ * Reset params to default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params);
+
+/*! ZSTD_CCtxParams_init() :
+ * Initializes the compression parameters of cctxParams according to
+ * compression level. All other parameters are reset to their default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel);
+
+/*! ZSTD_CCtxParams_init_advanced() :
+ * Initializes the compression and frame parameters of cctxParams according to
+ * params. All other parameters are reset to their default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
+
+/*! ZSTD_CCtxParam_setParameter() :
+ * Similar to ZSTD_CCtx_setParameter.
+ * Set one compression parameter, selected by enum ZSTD_cParameter.
+ * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value);
+
+/*! ZSTD_CCtxParam_getParameter() :
+ * Similar to ZSTD_CCtx_getParameter.
+ * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParam_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
+
+/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
+ * Apply a set of ZSTD_CCtx_params to the compression context.
+ * This can be done even after compression is started,
+ * if nbWorkers==0, this will have no impact until a new compression is started.
+ * if nbWorkers>=1, new parameters will be picked up at next job,
+ * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
+ ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
+
+/*! ZSTD_compressStream2_simpleArgs() :
+ * Same as ZSTD_compressStream2(),
+ * but using only integral types as arguments.
+ * This variant might be helpful for binders from dynamic languages
+ * which have troubles handling structures containing memory pointers.
+ */
+ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs (
+ ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos,
+ ZSTD_EndDirective endOp);
+
+
+/***************************************
+* Advanced decompression functions
+***************************************/
+
+/*! ZSTD_isFrame() :
+ * Tells if the content of `buffer` starts with a valid Frame Identifier.
+ * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
+ * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
+ * Note 3 : Skippable Frame Identifiers are considered valid. */
+ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
+
+/*! ZSTD_createDDict_byReference() :
+ * Create a digested dictionary, ready to start decompression operation without startup delay.
+ * Dictionary content is referenced, and therefore stays in dictBuffer.
+ * It is important that dictBuffer outlives DDict,
+ * it must remain read accessible throughout the lifetime of DDict */
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
+
+
+/*! ZSTD_getDictID_fromDict() :
+ * Provides the dictID stored within dictionary.
+ * if @return == 0, the dictionary is not conformant with Zstandard specification.
+ * It can still be loaded, but as a content-only dictionary. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
+
+/*! ZSTD_getDictID_fromDDict() :
+ * Provides the dictID of the dictionary loaded into `ddict`.
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
+
+/*! ZSTD_getDictID_fromFrame() :
+ * Provides the dictID required to decompressed the frame stored within `src`.
+ * If @return == 0, the dictID could not be decoded.
+ * This could for one of the following reasons :
+ * - The frame does not require a dictionary to be decoded (most common case).
+ * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
+ * Note : this use case also happens when using a non-conformant dictionary.
+ * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
+ * - This is not a Zstandard frame.
+ * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
+
+/*! ZSTD_DCtx_loadDictionary_byReference() :
+ * Same as ZSTD_DCtx_loadDictionary(),
+ * but references `dict` content instead of copying it into `dctx`.
+ * This saves memory if `dict` remains around.,
+ * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_DCtx_loadDictionary_advanced() :
+ * Same as ZSTD_DCtx_loadDictionary(),
+ * but gives direct control over
+ * how to load the dictionary (by copy ? by reference ?)
+ * and how to interpret it (automatic ? force raw mode ? full mode only ?). */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_DCtx_refPrefix_advanced() :
+ * Same as ZSTD_DCtx_refPrefix(), but gives finer control over
+ * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_DCtx_setMaxWindowSize() :
+ * Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
+ * This protects a decoder context from reserving too much memory for itself (potential attack scenario).
+ * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
+ * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT)
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
+
+/* ZSTD_d_format
+ * experimental parameter,
+ * allowing selection between ZSTD_format_e input compression formats
+ */
+#define ZSTD_d_format ZSTD_d_experimentalParam1
+
+/*! ZSTD_DCtx_setFormat() :
+ * Instruct the decoder context about what kind of data to decode next.
+ * This instruction is mandatory to decode data without a fully-formed header,
+ * such ZSTD_f_zstd1_magicless for example.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
+
+/*! ZSTD_decompressStream_simpleArgs() :
+ * Same as ZSTD_decompressStream(),
+ * but using only integral types as arguments.
+ * This can be helpful for binders from dynamic languages
+ * which have troubles handling structures containing memory pointers.
+ */
+ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
+ ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos);
+
+
+/********************************************************************
+* Advanced streaming functions
+* Warning : most of these functions are now redundant with the Advanced API.
+* Once Advanced API reaches "stable" status,
+* redundant functions will be deprecated, and then at some point removed.
+********************************************************************/
+
+/*===== Advanced Streaming compression functions =====*/
+ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct. If it is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, "0" also disables frame content size field. It may be enabled in the future. */
+ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
+ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
+ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */
+ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters. pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. */
+
+/*! ZSTD_resetCStream() :
+ * start a new frame, using same parameters from previous frame.
+ * This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
+ * Note that zcs must be init at least once before using ZSTD_resetCStream().
+ * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
+ * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
+ * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
+ * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError())
+ */
+ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
+
+
+typedef struct {
+ unsigned long long ingested; /* nb input bytes read and buffered */
+ unsigned long long consumed; /* nb input bytes actually compressed */
+ unsigned long long produced; /* nb of compressed bytes generated and buffered */
+ unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */
+ unsigned currentJobID; /* MT only : latest started job nb */
+ unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */
+} ZSTD_frameProgression;
+
+/* ZSTD_getFrameProgression() :
+ * tells how much data has been ingested (read from input)
+ * consumed (input actually compressed) and produced (output) for current frame.
+ * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed.
+ * Aggregates progression inside active worker threads.
+ */
+ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx);
+
+/*! ZSTD_toFlushNow() :
+ * Tell how many bytes are ready to be flushed immediately.
+ * Useful for multithreading scenarios (nbWorkers >= 1).
+ * Probe the oldest active job, defined as oldest job not yet entirely flushed,
+ * and check its output buffer.
+ * @return : amount of data stored in oldest job and ready to be flushed immediately.
+ * if @return == 0, it means either :
+ * + there is no active job (could be checked with ZSTD_frameProgression()), or
+ * + oldest job is still actively compressing data,
+ * but everything it has produced has also been flushed so far,
+ * therefore flush speed is limited by production speed of oldest job
+ * irrespective of the speed of concurrent (and newer) jobs.
+ */
+ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx);
+
+
+/*===== Advanced Streaming decompression functions =====*/
+ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
+ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict is referenced, it must outlive decompression session */
+ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */
+
+
+/*********************************************************************
+* Buffer-less and synchronous inner streaming functions
+*
+* This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
+* But it's also a complex one, with several restrictions, documented below.
+* Prefer normal streaming API for an easier experience.
+********************************************************************* */
+
+/**
+ Buffer-less streaming compression (synchronous mode)
+
+ A ZSTD_CCtx object is required to track streaming operations.
+ Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
+ ZSTD_CCtx object can be re-used multiple times within successive compression operations.
+
+ Start by initializing a context.
+ Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
+ or ZSTD_compressBegin_advanced(), for finer parameter control.
+ It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
+
+ Then, consume your input using ZSTD_compressContinue().
+ There are some important considerations to keep in mind when using this advanced function :
+ - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
+ - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
+ - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
+ Worst case evaluation is provided by ZSTD_compressBound().
+ ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
+ - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog).
+ It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks)
+ - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps.
+ In which case, it will "discard" the relevant memory section from its history.
+
+ Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
+ It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
+ Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
+
+ `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
+*/
+
+/*===== Buffer-less streaming compression functions =====*/
+ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
+ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */
+
+ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+
+/*-
+ Buffer-less streaming decompression (synchronous mode)
+
+ A ZSTD_DCtx object is required to track streaming operations.
+ Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
+ A ZSTD_DCtx object can be re-used multiple times.
+
+ First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
+ Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
+ Data fragment must be large enough to ensure successful decoding.
+ `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
+ @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled.
+ >0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
+ errorCode, which can be tested using ZSTD_isError().
+
+ It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
+ such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`).
+ Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information.
+ As a consequence, check that values remain within valid application range.
+ For example, do not allocate memory blindly, check that `windowSize` is within expectation.
+ Each application can set its own limits, depending on local restrictions.
+ For extended interoperability, it is recommended to support `windowSize` of at least 8 MB.
+
+ ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes.
+ ZSTD_decompressContinue() is very sensitive to contiguity,
+ if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
+ or that previous contiguous segment is large enough to properly handle maximum back-reference distance.
+ There are multiple ways to guarantee this condition.
+
+ The most memory efficient way is to use a round buffer of sufficient size.
+ Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(),
+ which can @return an error code if required value is too large for current system (in 32-bits mode).
+ In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one,
+ up to the moment there is not enough room left in the buffer to guarantee decoding another full block,
+ which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`.
+ At which point, decoding can resume from the beginning of the buffer.
+ Note that already decoded data stored in the buffer should be flushed before being overwritten.
+
+ There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory.
+
+ Finally, if you control the compression process, you can also ignore all buffer size rules,
+ as long as the encoder and decoder progress in "lock-step",
+ aka use exactly the same buffer sizes, break contiguity at the same place, etc.
+
+ Once buffers are setup, start decompression, with ZSTD_decompressBegin().
+ If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict().
+
+ Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
+ ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
+ ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
+
+ @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
+ It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item.
+ It can also be an error code, which can be tested with ZSTD_isError().
+
+ A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
+ Context can then be reset to start a new decompression.
+
+ Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType().
+ This information is not required to properly decode a frame.
+
+ == Special case : skippable frames ==
+
+ Skippable frames allow integration of user-defined data into a flow of concatenated frames.
+ Skippable frames will be ignored (skipped) by decompressor.
+ The format of skippable frames is as follows :
+ a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
+ b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
+ c) Frame Content - any content (User Data) of length equal to Frame Size
+ For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame.
+ For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
+*/
+
+/*===== Buffer-less streaming decompression functions =====*/
+typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
+typedef struct {
+ unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */
+ unsigned long long windowSize; /* can be very large, up to <= frameContentSize */
+ unsigned blockSizeMax;
+ ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */
+ unsigned headerSize;
+ unsigned dictID;
+ unsigned checksumFlag;
+} ZSTD_frameHeader;
+
+/** ZSTD_getFrameHeader() :
+ * decode Frame Header, or requires larger `srcSize`.
+ * @return : 0, `zfhPtr` is correctly filled,
+ * >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ * or an error code, which can be tested using ZSTD_isError() */
+ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */
+/*! ZSTD_getFrameHeader_advanced() :
+ * same as ZSTD_getFrameHeader(),
+ * with added capability to select a format (like ZSTD_f_zstd1_magicless) */
+ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
+ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */
+
+ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+/* misc */
+ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
+typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
+ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
+
+
+
+
+/* ============================ */
+/** Block level API */
+/* ============================ */
+
+/*!
+ Block functions produce and decode raw zstd blocks, without frame metadata.
+ Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
+ User will have to take in charge required information to regenerate data, such as compressed and content sizes.
+
+ A few rules to respect :
+ - Compressing and decompressing require a context structure
+ + Use ZSTD_createCCtx() and ZSTD_createDCtx()
+ - It is necessary to init context before starting
+ + compression : any ZSTD_compressBegin*() variant, including with dictionary
+ + decompression : any ZSTD_decompressBegin*() variant, including with dictionary
+ + copyCCtx() and copyDCtx() can be used too
+ - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
+ + If input is larger than a block size, it's necessary to split input data into multiple blocks
+ + For inputs larger than a single block, really consider using regular ZSTD_compress() instead.
+ Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
+ - When a block is considered not compressible enough, ZSTD_compressBlock() result will be zero.
+ In which case, nothing is produced into `dst` !
+ + User must test for such outcome and deal directly with uncompressed data
+ + ZSTD_decompressBlock() doesn't accept uncompressed data as input !!!
+ + In case of multiple successive blocks, should some of them be uncompressed,
+ decoder must be informed of their existence in order to follow proper history.
+ Use ZSTD_insertBlock() for such a case.
+*/
+
+/*===== Raw zstd block functions =====*/
+ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */
+
+
+#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/bootstrap b/bootstrap
index 26c521250..38fa32b5b 100755
--- a/bootstrap
+++ b/bootstrap
@@ -260,6 +260,7 @@ CMAKE_CXX_SOURCES="\
cmAddLibraryCommand \
cmAddSubDirectoryCommand \
cmAddTestCommand \
+ cmArgumentParser \
cmBreakCommand \
cmBuildCommand \
cmCMakeMinimumRequired \
@@ -268,7 +269,6 @@ CMAKE_CXX_SOURCES="\
cmCacheManager \
cmCommand \
cmCommandArgumentParserHelper \
- cmCommandArgumentsHelper \
cmCommands \
cmCommonTargetGenerator \
cmComputeComponentGraph \
@@ -302,7 +302,11 @@ CMAKE_CXX_SOURCES="\
cmExprParserHelper \
cmExternalMakefileProjectGenerator \
cmFileCommand \
- cmFileTimeComparison \
+ cmFileCopier \
+ cmFileInstaller \
+ cmFileTime \
+ cmFileTimeCache \
+ cmFileTimes \
cmFindBase \
cmFindCommon \
cmFindFileCommand \
@@ -326,6 +330,7 @@ CMAKE_CXX_SOURCES="\
cmGetCMakePropertyCommand \
cmGetDirectoryPropertyCommand \
cmGetFilenameComponentCommand \
+ cmGetPipes \
cmGetPropertyCommand \
cmGetSourceFilePropertyCommand \
cmGetTargetPropertyCommand \
@@ -355,6 +360,7 @@ CMAKE_CXX_SOURCES="\
cmLinkDirectoriesCommand \
cmLinkItem \
cmLinkLineComputer \
+ cmLinkLineDeviceComputer \
cmListCommand \
cmListFileCache \
cmLocalCommonGenerator \
@@ -424,6 +430,7 @@ CMAKE_CXX_SOURCES="\
cmUnexpectedCommand \
cmUnsetCommand \
cmUVHandlePtr \
+ cmUVProcessChain \
cmVersion \
cmWhileCommand \
cmWorkingDirectory \
@@ -573,6 +580,8 @@ Configuration:
--no-system-bzip2 use cmake-provided bzip2 library (default)
--system-liblzma use system-installed liblzma library
--no-system-liblzma use cmake-provided liblzma library (default)
+ --system-zstd use system-installed zstd library
+ --no-system-zstd use cmake-provided zstd library (default)
--system-libarchive use system-installed libarchive library
--no-system-libarchive use cmake-provided libarchive library (default)
--system-librhash use system-installed librhash library
@@ -680,6 +689,7 @@ cmake_kwsys_config_replace_string ()
s/@KWSYS_NAME_IS_KWSYS@/${KWSYS_NAME_IS_KWSYS}/g;
s/@KWSYS_STL_HAS_WSTRING@/${KWSYS_STL_HAS_WSTRING}/g;
s/@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@/${KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H}/g;
+ s/@KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@/${KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP}/g;
}" "${INFILE}" >> "${OUTFILE}${_tmp}"
if [ -f "${OUTFILE}${_tmp}" ]; then
if "${_diff}" "${OUTFILE}" "${OUTFILE}${_tmp}" > /dev/null 2> /dev/null ; then
@@ -814,10 +824,10 @@ while test $# != 0; do
--init=*) cmake_init_file=`cmake_arg "$1"` ;;
--system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=1" ;;
--no-system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=0" ;;
- --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-libuv)
+ --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-zstd|--system-libuv)
lib=`cmake_arg "$1" "--system-"`
cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=1" ;;
- --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-libuv)
+ --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-zstd|--no-system-libuv)
lib=`cmake_arg "$1" "--no-system-"`
cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=0" ;;
--qt-gui) cmake_bootstrap_qt_gui="1" ;;
@@ -1212,6 +1222,7 @@ KWSYS_CXX_HAS_UNSETENV=0
KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=0
KWSYS_CXX_HAS_UTIMENSAT=0
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" \